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

📄 h8300.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* Figure out the logical op that we need to perform.  */  enum rtx_code code = GET_CODE (operands[3]);  /* Pretend that every byte is affected if both operands are registers.  */  unsigned HOST_WIDE_INT intval =    (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)			      ? INTVAL (operands[2]) : 0x55555555);  /* The determinant of the algorithm.  If we perform an AND, 0     affects a bit.  Otherwise, 1 affects a bit.  */  unsigned HOST_WIDE_INT det = (code != AND) ? intval : ~intval;  /* Insn length.  */  unsigned int length = 0;  switch (mode)    {    case HImode:      /* First, see if we can finish with one insn.  */      if ((TARGET_H8300H || TARGET_H8300S)	  && ((det & 0x00ff) != 0)	  && ((det & 0xff00) != 0))	{	  if (REG_P (operands[2]))	    length += 2;	  else	    length += 4;	}      else	{	  /* Take care of the lower byte.  */	  if ((det & 0x00ff) != 0)	    length += 2;	  /* Take care of the upper byte.  */	  if ((det & 0xff00) != 0)	    length += 2;	}      break;    case SImode:      /* First, see if we can finish with one insn.	 If code is either AND or XOR, we exclude two special cases,	 0xffffff00 and 0xffff00ff, because insns like sub.w or not.w	 can do a better job.  */      if ((TARGET_H8300H || TARGET_H8300S)	  && ((det & 0x0000ffff) != 0)	  && ((det & 0xffff0000) != 0)	  && (code == IOR || det != 0xffffff00)	  && (code == IOR || det != 0xffff00ff))	{	  if (REG_P (operands[2]))	    length += 4;	  else	    length += 6;	}      else	{	  /* Take care of the lower and upper words individually.  For	     each word, we try different methods in the order of	     1) the special insn (in case of AND or XOR),	     2) the word-wise insn, and	     3) The byte-wise insn.  */	  if ((det & 0x0000ffff) == 0x0000ffff	      && (TARGET_H8300 ? (code == AND) : (code != IOR)))	    {	      length += 2;	    }	  else if ((TARGET_H8300H || TARGET_H8300S)		   && ((det & 0x000000ff) != 0)		   && ((det & 0x0000ff00) != 0))	    {	      length += 4;	    }	  else	    {	      if ((det & 0x000000ff) != 0)		length += 2;	      if ((det & 0x0000ff00) != 0)		length += 2;	    }	  if ((det & 0xffff0000) == 0xffff0000	      && (TARGET_H8300 ? (code == AND) : (code != IOR)))	    {	      length += 2;	    }	  else if (TARGET_H8300H || TARGET_H8300S)	    {	      if ((det & 0xffff0000) != 0)		length += 4;	    }	  else	    {	      if ((det & 0x00ff0000) != 0)		length += 2;	      if ((det & 0xff000000) != 0)		length += 2;	    }	}      break;    default:      abort ();    }  return length;}intcompute_logical_op_cc (mode, operands)     enum machine_mode mode;     rtx *operands;{  /* Figure out the logical op that we need to perform.  */  enum rtx_code code = GET_CODE (operands[3]);  /* Pretend that every byte is affected if both operands are registers.  */  unsigned HOST_WIDE_INT intval =    (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)			      ? INTVAL (operands[2]) : 0x55555555);  /* The determinant of the algorithm.  If we perform an AND, 0     affects a bit.  Otherwise, 1 affects a bit.  */  unsigned HOST_WIDE_INT det = (code != AND) ? intval : ~intval;  /* Condition code.  */  enum attr_cc cc = CC_CLOBBER;  switch (mode)    {    case HImode:      /* First, see if we can finish with one insn.  */      if ((TARGET_H8300H || TARGET_H8300S)	  && ((det & 0x00ff) != 0)	  && ((det & 0xff00) != 0))	{	  cc = CC_SET_ZNV;	}      break;    case SImode:      /* First, see if we can finish with one insn.	 If code is either AND or XOR, we exclude two special cases,	 0xffffff00 and 0xffff00ff, because insns like sub.w or not.w	 can do a better job.  */      if ((TARGET_H8300H || TARGET_H8300S)	  && ((det & 0x0000ffff) != 0)	  && ((det & 0xffff0000) != 0)	  && (code == IOR || det != 0xffffff00)	  && (code == IOR || det != 0xffff00ff))	{	  cc = CC_SET_ZNV;	}      break;    default:      abort ();    }  return cc;}/* Shifts.   We devote a fair bit of code to getting efficient shifts since we   can only shift one bit at a time on the H8/300 and H8/300H and only   one or two bits at a time on the H8S.   All shift code falls into one of the following ways of   implementation:   o SHIFT_INLINE: Emit straight line code for the shift; this is used     when a straight line shift is about the same size or smaller than     a loop.   o SHIFT_ROT_AND: Rotate the value the opposite direction, then mask     off the bits we don't need.  This is used when only a few of the     bits in the original value will survive in the shifted value.   o SHIFT_SPECIAL: Often it's possible to move a byte or a word to     simulate a shift by 8, 16, or 24 bits.  Once moved, a few inline     shifts can be added if the shift count is slightly more than 8 or     16.  This case also includes other oddballs that are not worth     explaning here.   o SHIFT_LOOP: Emit a loop using one (or two on H8S) bit shifts.   For each shift count, we try to use code that has no trade-off   between code size and speed whenever possible.   If the trade-off is unavoidable, we try to be reasonable.   Specifically, the fastest version is one instruction longer than   the shortest version, we take the fastest version.  We also provide   the use a way to switch back to the shortest version with -Os.   For the details of the shift algorithms for various shift counts,   refer to shift_alg_[qhs]i.  */intnshift_operator (x, mode)     rtx x;     enum machine_mode mode ATTRIBUTE_UNUSED;{  switch (GET_CODE (x))    {    case ASHIFTRT:    case LSHIFTRT:    case ASHIFT:      return 1;    default:      return 0;    }}/* Called from the .md file to emit code to do shifts.   Return a boolean indicating success.   (Currently this is always TRUE).  */intexpand_a_shift (mode, code, operands)     enum machine_mode mode;     int code;     rtx operands[];{  emit_move_insn (operands[0], operands[1]);  /* Need a loop to get all the bits we want  - we generate the     code at emit time, but need to allocate a scratch reg now.  */  emit_insn (gen_rtx_PARALLEL	     (VOIDmode,	      gen_rtvec (2,			 gen_rtx_SET (VOIDmode, operands[0],				      gen_rtx (code, mode, operands[0],					       operands[2])),			 gen_rtx_CLOBBER (VOIDmode,					  gen_rtx_SCRATCH (QImode)))));  return 1;}/* Symbols of the various modes which can be used as indices.  */enum shift_mode{  QIshift, HIshift, SIshift};/* For single bit shift insns, record assembler and what bits of the   condition code are valid afterwards (represented as various CC_FOO   bits, 0 means CC isn't left in a usable state).  */struct shift_insn{  const char *const assembler;  const int cc_valid;};/* Assembler instruction shift table.   These tables are used to look up the basic shifts.   They are indexed by cpu, shift_type, and mode.  */static const struct shift_insn shift_one[2][3][3] ={/* H8/300 */  {/* SHIFT_ASHIFT */    {      { "shll\t%X0", CC_NO_CARRY },      { "add.w\t%T0,%T0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "add.w\t%f0,%f0\n\taddx\t%y0,%y0\n\taddx\t%z0,%z0", 0 }    },/* SHIFT_LSHIFTRT */    {      { "shlr\t%X0", CC_NO_CARRY },      { "shlr\t%t0\n\trotxr\t%s0", 0 },      { "shlr\t%z0\n\trotxr\t%y0\n\trotxr\t%x0\n\trotxr\t%w0", 0 }    },/* SHIFT_ASHIFTRT */    {      { "shar\t%X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "shar\t%t0\n\trotxr\t%s0", 0 },      { "shar\t%z0\n\trotxr\t%y0\n\trotxr\t%x0\n\trotxr\t%w0", 0 }    }  },/* H8/300H */  {/* SHIFT_ASHIFT */    {      { "shll.b\t%X0", CC_NO_CARRY },      { "shll.w\t%T0", CC_NO_CARRY },      { "shll.l\t%S0", CC_NO_CARRY }    },/* SHIFT_LSHIFTRT */    {      { "shlr.b\t%X0", CC_NO_CARRY },      { "shlr.w\t%T0", CC_NO_CARRY },      { "shlr.l\t%S0", CC_NO_CARRY }    },/* SHIFT_ASHIFTRT */    {      { "shar.b\t%X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "shar.w\t%T0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "shar.l\t%S0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY }    }  }};static const struct shift_insn shift_two[3][3] ={/* SHIFT_ASHIFT */    {      { "shll.b\t#2,%X0", CC_NO_CARRY },      { "shll.w\t#2,%T0", CC_NO_CARRY },      { "shll.l\t#2,%S0", CC_NO_CARRY }    },/* SHIFT_LSHIFTRT */    {      { "shlr.b\t#2,%X0", CC_NO_CARRY },      { "shlr.w\t#2,%T0", CC_NO_CARRY },      { "shlr.l\t#2,%S0", CC_NO_CARRY }    },/* SHIFT_ASHIFTRT */    {      { "shar.b\t#2,%X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "shar.w\t#2,%T0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },      { "shar.l\t#2,%S0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY }    }};/* Rotates are organized by which shift they'll be used in implementing.   There's no need to record whether the cc is valid afterwards because   it is the AND insn that will decide this.  */static const char *const rotate_one[2][3][3] ={/* H8/300 */  {/* SHIFT_ASHIFT */    {      "rotr\t%X0",      "shlr\t%t0\n\trotxr\t%s0\n\tbst\t#7,%t0",      0    },/* SHIFT_LSHIFTRT */    {      "rotl\t%X0",      "shll\t%s0\n\trotxl\t%t0\n\tbst\t#0,%s0",      0    },/* SHIFT_ASHIFTRT */    {      "rotl\t%X0",      "shll\t%s0\n\trotxl\t%t0\n\tbst\t#0,%s0",      0    }  },/* H8/300H */  {/* SHIFT_ASHIFT */    {      "rotr.b\t%X0",      "rotr.w\t%T0",      "rotr.l\t%S0"    },/* SHIFT_LSHIFTRT */    {      "rotl.b\t%X0",      "rotl.w\t%T0",      "rotl.l\t%S0"    },/* SHIFT_ASHIFTRT */    {      "rotl.b\t%X0",      "rotl.w\t%T0",      "rotl.l\t%S0"    }  }};static const char *const rotate_two[3][3] ={/* SHIFT_ASHIFT */    {      "rotr.b\t#2,%X0",      "rotr.w\t#2,%T0",      "rotr.l\t#2,%S0"    },/* SHIFT_LSHIFTRT */    {      "rotl.b\t#2,%X0",      "rotl.w\t#2,%T0",      "rotl.l\t#2,%S0"    },/* SHIFT_ASHIFTRT */    {      "rotl.b\t#2,%X0",      "rotl.w\t#2,%T0",      "rotl.l\t#2,%S0"    }};struct shift_info {  /* Shift algorithm.  */  enum shift_alg alg;  /* The number of bits to be shifted by shift1 and shift2.  Valid     when ALG is SHIFT_SPECIAL.  */  unsigned int remainder;  /* Special insn for a shift.  Valid when ALG is SHIFT_SPECIAL.  */  const char *special;  /* Insn for a one-bit shift.  Valid when ALG is either SHIFT_INLINE     or SHIFT_SPECIAL, and REMAINDER is nonzero.  */  const char *shift1;  /* Insn for a two-bit shift.  Valid when ALG is either SHIFT_INLINE     or SHIFT_SPECIAL, and REMAINDER is nonzero.  */  const char *shift2;  /* Valid CC flags.  */  int cc_valid_p;};static void get_shift_alg PARAMS ((enum shift_type,				   enum shift_mode, unsigned int,				   struct shift_info *));/* Given SHIFT_TYPE, SHIFT_MODE, and shift count COUNT, determine the   best algorithm for doing the shift.  The assembler code is stored   in the pointers in INFO.  We achieve the maximum efficiency in most   cases when !TARGET_H8300.  In case of TARGET_H8300, shifts in   SImode in particular have a lot of room to optimize.   We first determine the strategy of the shift algorithm by a table   lookup.  If that tells us to use a hand crafted assembly code, we   go into the big switch statement to find what that is.  Otherwise,   we resort to a generic way, such as inlining.  In either case, the   result is returned through INFO.  */static voidget_shift_alg (shift_type, shift_mode, count, info)     enum shift_type shift_type;     enum shift_mode shift_mode;     unsigned int count;     struct shift_info *info;{  enum h8_cpu cpu;  /* Find the target CPU.  */  if (TARGET_H8300)    cpu = H8_300;  else if (TARGET_H8300H)    cpu = H8_300H;  else    cpu = H8_S;  /* Find the shift algorithm.  */  info->alg = SHIFT_LOOP;  switch (shift_mode)    {    case QIshift:      if (count < GET_MODE_BITSIZE (QImode))	info->alg = shift_alg_qi[cpu][shift_type][count];      break;    case HIshift:      if (count < GET_MODE_BITSIZE (HImode))	info->alg = shift_alg_hi[cpu][shift_type][count];      break;    case SIshift:      if (count < GET_MODE_BITSIZE (SImode))	info->alg = shift_alg_si[cpu][shift_type][count];      break;    default:      abort ();    }  /* Fill in INFO.  Return unless we have SHIFT_SPECIAL.  */  switch (info->alg)    {    case SHIFT_INLINE:      info->remainder = count;      /* Fall through.  */    case SHIFT_LOOP:      /* It is up to the caller to know that looping clobbers cc.  */      info->shift1 = shift_one[cpu_type][shift_type][shift_mode].assembler;      info->shift2 = shift_two[shift_type][shift_mode].assembler;      info->cc_valid_p = shift_one[cpu_type][shift_type][shift_mode].cc_valid;      goto end;    case SHIFT_ROT_AND:      info->shift1 = rotate_one[cpu_type][shift_type][shift_mode];      info->shift2 = rotate_two[shift_type][shift_mode];      info->cc_valid_p = 0;      goto end;    case SHIFT_SPECIAL:      /* REMAINDER is 0 for most cases, so initialize it to 0.  */      info->remainder = 0;      info->shift1 = shift_one[cpu_type][shift_type][shift_mode].assembler;      info->s

⌨️ 快捷键说明

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