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

📄 m88k.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Motorola 88000.   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,   2001, 2002 Free Software Foundation, Inc.    Contributed by Michael Tiemann (tiemann@mcc.com)   Currently maintained by (gcc@dg-rtp.dg.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 "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 "tree.h"#include "function.h"#include "expr.h"#include "libfuncs.h"#include "c-tree.h"#include "flags.h"#include "recog.h"#include "toplev.h"#include "tm_p.h"#include "target.h"#include "target-def.h"extern FILE *asm_out_file;const char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */const char *m88k_short_data;const char *m88k_version;char m88k_volatile_code;unsigned m88k_gp_threshold = 0;int m88k_prologue_done	= 0;	/* Ln directives can now be emitted */int m88k_function_number = 0;	/* Counter unique to each function */int m88k_fp_offset	= 0;	/* offset of frame pointer if used */int m88k_stack_size	= 0;	/* size of allocated stack (including frame) */int m88k_case_index;rtx m88k_compare_reg;		/* cmp output pseudo register */rtx m88k_compare_op0;		/* cmpsi operand 0 */rtx m88k_compare_op1;		/* cmpsi operand 1 */enum processor_type m88k_cpu;	/* target cpu */static void m88k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void m88k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void m88k_output_function_end_prologue PARAMS ((FILE *));static void m88k_output_function_begin_epilogue PARAMS ((FILE *));#if defined (CTOR_LIST_BEGIN) && !defined (OBJECT_FORMAT_ELF)static void m88k_svr3_asm_out_constructor PARAMS ((rtx, int));static void m88k_svr3_asm_out_destructor PARAMS ((rtx, int));#endifstatic void m88k_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));static int m88k_adjust_cost PARAMS ((rtx, rtx, rtx, int));static void m88k_encode_section_info PARAMS ((tree, int));/* Initialize the GCC target structure.  */#undef TARGET_ASM_BYTE_OP#define TARGET_ASM_BYTE_OP "\tbyte\t"#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\thalf\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\tword\t"#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP "\tuahalf\t"#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP "\tuaword\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE m88k_output_function_prologue#undef TARGET_ASM_FUNCTION_END_PROLOGUE#define TARGET_ASM_FUNCTION_END_PROLOGUE m88k_output_function_end_prologue#undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE#define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE m88k_output_function_begin_epilogue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE m88k_output_function_epilogue#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST m88k_adjust_cost#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO  m88k_encode_section_infostruct gcc_target targetm = TARGET_INITIALIZER;/* Determine what instructions are needed to manufacture the integer VALUE   in the given MODE.  */enum m88k_instructionclassify_integer (mode, value)     enum machine_mode mode;     register int value;{  if (value == 0)    return m88k_zero;  else if (SMALL_INTVAL (value))    return m88k_or;  else if (SMALL_INTVAL (-value))    return m88k_subu;  else if (mode == HImode)    return m88k_or_lo16;  else if (mode == QImode)    return m88k_or_lo8;  else if ((value & 0xffff) == 0)    return m88k_oru_hi16;  else if (integer_ok_for_set (value))    return m88k_set;  else    return m88k_oru_or;}/* Return the bit number in a compare word corresponding to CONDITION.  */intcondition_value (condition)     rtx condition;{  switch (GET_CODE (condition))    {    case EQ: return 2;    case NE: return 3;    case GT: return 4;    case LE: return 5;    case LT: return 6;    case GE: return 7;    case GTU: return 8;    case LEU: return 9;    case LTU: return 10;    case GEU: return 11;    default: abort ();    }}intinteger_ok_for_set (value)     register unsigned value;{  /* All the "one" bits must be contiguous.  If so, MASK + 1 will be     a power of two or zero.  */  register unsigned mask = (value | (value - 1));  return (value && POWER_OF_2_or_0 (mask + 1));}const char *output_load_const_int (mode, operands)     enum machine_mode mode;     rtx *operands;{  static const char *const patterns[] =    { "or %0,%#r0,0",      "or %0,%#r0,%1",      "subu %0,%#r0,%n1",      "or %0,%#r0,%h1",      "or %0,%#r0,%q1",      "set %0,%#r0,%s1",      "or.u %0,%#r0,%X1",      "or.u %0,%#r0,%X1\n\tor %0,%0,%x1",    };  if (! REG_P (operands[0])      || GET_CODE (operands[1]) != CONST_INT)    abort ();  return patterns[classify_integer (mode, INTVAL (operands[1]))];}/* These next two routines assume that floating point numbers are represented   in a manner which is consistent between host and target machines.  */const char *output_load_const_float (operands)     rtx *operands;{  /* These can return 0 under some circumstances when cross-compiling.  */  operands[0] = operand_subword (operands[0], 0, 0, SFmode);  operands[1] = operand_subword (operands[1], 0, 0, SFmode);  return output_load_const_int (SImode, operands);}const char *output_load_const_double (operands)     rtx *operands;{  rtx latehalf[2];  /* These can return zero on some cross-compilers, but there's nothing     we can do about it.  */  latehalf[0] = operand_subword (operands[0], 1, 0, DFmode);  latehalf[1] = operand_subword (operands[1], 1, 0, DFmode);  operands[0] = operand_subword (operands[0], 0, 0, DFmode);  operands[1] = operand_subword (operands[1], 0, 0, DFmode);  output_asm_insn (output_load_const_int (SImode, operands), operands);  operands[0] = latehalf[0];  operands[1] = latehalf[1];  return output_load_const_int (SImode, operands);}const char *output_load_const_dimode (operands)     rtx *operands;{  rtx latehalf[2];  latehalf[0] = operand_subword (operands[0], 1, 0, DImode);  latehalf[1] = operand_subword (operands[1], 1, 0, DImode);  operands[0] = operand_subword (operands[0], 0, 0, DImode);  operands[1] = operand_subword (operands[1], 0, 0, DImode);  output_asm_insn (output_load_const_int (SImode, operands), operands);  operands[0] = latehalf[0];  operands[1] = latehalf[1];  return output_load_const_int (SImode, operands);}/* Emit insns to move operands[1] into operands[0].   Return 1 if we have written out everything that needs to be done to   do the move.  Otherwise, return 0 and the caller will emit the move   normally.   SCRATCH if nonzero can be used as a scratch register for the move   operation.  It is provided by a SECONDARY_RELOAD_* macro if needed.  */intemit_move_sequence (operands, mode, scratch)     rtx *operands;     enum machine_mode mode;     rtx scratch;{  register rtx operand0 = operands[0];  register rtx operand1 = operands[1];  if (CONSTANT_P (operand1) && flag_pic      && pic_address_needs_scratch (operand1))    operands[1] = operand1 = legitimize_address (1, operand1, 0, 0);  /* Handle most common case first: storing into a register.  */  if (register_operand (operand0, mode))    {      if (register_operand (operand1, mode)	  || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))	  || GET_CODE (operand1) == HIGH	  /* Only `general_operands' can come here, so MEM is ok.  */	  || GET_CODE (operand1) == MEM)	{	  /* Run this case quickly.  */	  emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));	  return 1;	}    }  else if (GET_CODE (operand0) == MEM)    {      if (register_operand (operand1, mode)	  || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))	{	  /* Run this case quickly.  */	  emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));	  return 1;	}      if (! reload_in_progress && ! reload_completed)	{	  operands[0] = validize_mem (operand0);	  operands[1] = operand1 = force_reg (mode, operand1);	}    }  /* Simplify the source if we need to.  */  if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))    {      if (GET_CODE (operand1) != CONST_INT	  && GET_CODE (operand1) != CONST_DOUBLE)	{	  rtx temp = ((reload_in_progress || reload_completed)		      ? operand0 : 0);	  operands[1] = legitimize_address (flag_pic					    && symbolic_address_p (operand1),					    operand1, temp, scratch);	  if (mode != SImode)	    operands[1] = gen_rtx_SUBREG (mode, operands[1], 0);	}    }  /* Now have insn-emit do whatever it normally does.  */  return 0;}/* Return a legitimate reference for ORIG (either an address or a MEM)   using the register REG.  If PIC and the address is already   position-independent, use ORIG.  Newly generated position-independent   addresses go into a reg.  This is REG if nonzero, otherwise we   allocate register(s) as necessary.  If this is called during reload,   and we need a second temp register, then we use SCRATCH, which is   provided via the SECONDARY_INPUT_RELOAD_CLASS mechanism.  */struct rtx_def *legitimize_address (pic, orig, reg, scratch)     int pic;     rtx orig;     rtx reg;     rtx scratch;{  rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig);  rtx new = orig;  rtx temp, insn;  if (pic)    {      if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)	{	  if (reg == 0)	    {	      if (reload_in_progress || reload_completed)		abort ();	      else		reg = gen_reg_rtx (Pmode);	    }	  if (flag_pic == 2)	    {	      /* If not during reload, allocate another temp reg here for		 loading in the address, so that these instructions can be		 optimized properly.  */	      temp = ((reload_in_progress || reload_completed)		      ? reg : gen_reg_rtx (Pmode));	      emit_insn (gen_rtx_SET			 (VOIDmode, temp,			  gen_rtx_HIGH (SImode,					gen_rtx_UNSPEC (SImode,							gen_rtvec (1, addr),							0))));	      emit_insn (gen_rtx_SET			 (VOIDmode, temp,			  gen_rtx_LO_SUM (SImode, temp,					  gen_rtx_UNSPEC (SImode,							  gen_rtvec (1, addr),							  0))));	      addr = temp;	    }	  new = gen_rtx_MEM (Pmode,			     gen_rtx_PLUS (SImode,					   pic_offset_table_rtx, addr));	  current_function_uses_pic_offset_table = 1;	  RTX_UNCHANGING_P (new) = 1;	  insn = emit_move_insn (reg, new);	  /* Put a REG_EQUAL note on this insn, so that it can be optimized	     by loop.  */	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,						REG_NOTES (insn));	  new = reg;	}      else if (GET_CODE (addr) == CONST)	{	  rtx base;	  if (GET_CODE (XEXP (addr, 0)) == PLUS	      && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx)	    return orig;	  if (reg == 0)	    {	      if (reload_in_progress || reload_completed)		abort ();	      else		reg = gen_reg_rtx (Pmode);	    }	  if (GET_CODE (XEXP (addr, 0)) != PLUS) abort ();	  base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg, 0);	  addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1),				     base == reg ? 0 : reg, 0);	  if (GET_CODE (addr) == CONST_INT)	    {	      if (ADD_INT (addr))		return plus_constant (base, INTVAL (addr));	      else if (! reload_in_progress && ! reload_completed)		addr = force_reg (Pmode, addr);	      /* We can't create any new registers during reload, so use the		 SCRATCH reg provided by the reload_insi pattern.  */	      else if (scratch)		{		  emit_move_insn (scratch, addr);		  addr = scratch;		}	      else		/* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS		   macro needs to be adjusted so that a scratch reg is provided		   for this address.  */		abort ();	    }	  new = gen_rtx_PLUS (SImode, base, addr);	  /* Should we set special REG_NOTEs here?  */	}    }  else if (! SHORT_ADDRESS_P (addr, temp))    {      if (reg == 0)	{	  if (reload_in_progress || reload_completed)	    abort ();	  else	    reg = gen_reg_rtx (Pmode);	}      emit_insn (gen_rtx_SET (VOIDmode,			      reg, gen_rtx_HIGH (SImode, addr)));      new = gen_rtx_LO_SUM (SImode, reg, addr);    }  if (new != orig      && GET_CODE (orig) == MEM)    {      new = gen_rtx_MEM (GET_MODE (orig), new);      MEM_COPY_ATTRIBUTES (new, orig);    }  return new;}/* Support functions for code to emit a block move.  There are four methods   used to perform the block move:   + call memcpy   + call the looping library function, e.g. __movstrSI64n8   + call a non-looping library function, e.g. __movstrHI15x11   + produce an inline sequence of ld/st instructions   The parameters below describe the library functions produced by   movstr-m88k.sh.  */#define MOVSTR_LOOP	64 /* __movstrSI64n68 .. __movstrSI64n8 */#define MOVSTR_QI	16 /* __movstrQI16x16 .. __movstrQI16x2 */#define MOVSTR_HI	48 /* __movstrHI48x48 .. __movstrHI48x4 */#define MOVSTR_SI	96 /* __movstrSI96x96 .. __movstrSI96x8 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -