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

📄 m88k.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Motorola 88000.   Copyright (C) 1988, 92, 93, 94, 95, 16, 1997, 1999 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 <stdio.h>#include <sys/types.h>#include <time.h>#include <ctype.h>#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "tree.h"#include "c-tree.h"#include "expr.h"#include "flags.h"extern char *version_string;extern time_t time ();extern char *ctime ();extern int flag_traditional;extern FILE *asm_out_file;static char out_rcs_id[] = "$What: <@(#) m88k.c,v	1.8> $";static char tm_rcs_id [] = TM_RCS_ID;char *m88k_pound_sign = "";	/* Either # for SVR4 or empty for SVR3 */char *m88k_short_data;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 *//* 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;{  register int mask;  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));}char *output_load_const_int (mode, operands)     enum machine_mode mode;     rtx *operands;{  static char *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.  */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);}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);}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 non zero 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 non zero, 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, offset;	  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_for_output (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);      RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (orig);      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 */#define MOVSTR_DI	96 /* __movstrDI96x96 .. __movstrDI96x16 */#define MOVSTR_ODD_HI	16 /* __movstrHI15x15 .. __movstrHI15x5 */#define MOVSTR_ODD_SI	48 /* __movstrSI47x47 .. __movstrSI47x11,			      __movstrSI46x46 .. __movstrSI46x10,			      __movstrSI45x45 .. __movstrSI45x9 */#define MOVSTR_ODD_DI	48 /* __movstrDI47x47 .. __movstrDI47x23,			      __movstrDI46x46 .. __movstrDI46x22,			      __movstrDI45x45 .. __movstrDI45x21,			      __movstrDI44x44 .. __movstrDI44x20,			      __movstrDI43x43 .. __movstrDI43x19,			      __movstrDI42x42 .. __movstrDI42x18,			      __movstrDI41x41 .. __movstrDI41x17 *//* Limits for using the non-looping movstr functions.  For the m88100   processor, we assume the source and destination are word aligned.   The QImode and HImode limits are the break even points where memcpy   does just as well and beyond which memcpy does better.  For the   m88110, we tend to assume double word alignment, but also analyze   the word aligned cases.  The analysis is complicated because memcpy   may use the cache control instructions for better performance.  */#define MOVSTR_QI_LIMIT_88100   13#define MOVSTR_HI_LIMIT_88100   38#define MOVSTR_SI_LIMIT_88100   MOVSTR_SI#define MOVSTR_DI_LIMIT_88100   MOVSTR_SI  #define MOVSTR_QI_LIMIT_88000   16#define MOVSTR_HI_LIMIT_88000   38#define MOVSTR_SI_LIMIT_88000   72#define MOVSTR_DI_LIMIT_88000   72#define MOVSTR_QI_LIMIT_88110   16#define MOVSTR_HI_LIMIT_88110   38#define MOVSTR_SI_LIMIT_88110   72#define MOVSTR_DI_LIMIT_88110   72static enum machine_mode mode_from_align[] =			      {VOIDmode, QImode, HImode, VOIDmode, SImode,			       VOIDmode, VOIDmode, VOIDmode, DImode};static int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI,			       0, 0, 0, MOVSTR_DI};static int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0, MOVSTR_ODD_SI,			       0, 0, 0, MOVSTR_ODD_DI};static int best_from_align[3][9] =

⌨️ 快捷键说明

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