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

📄 arm.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		 the rest are diadic.  */	      emit_insn (gen_rtx (SET, VOIDmode, target, GEN_INT (val)));	      return 1;	    }	  else	    {	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_rtx (SET, VOIDmode, temp, GEN_INT (val)));	      /* For MINUS, the value is subtracted from, since we never		 have subtraction of a constant.  */	      if (code == MINUS)		emit_insn (gen_rtx (SET, VOIDmode, target,				    gen_rtx (code, mode, temp, source)));	      else		emit_insn (gen_rtx (SET, VOIDmode, target,				    gen_rtx (code, mode, source, temp)));	      return 2;	    }	}    }  return arm_gen_constant (code, mode, val, target, source, subtargets, 1);}/* As above, but extra parameter GENERATE which, if clear, suppresses   RTL generation.  */intarm_gen_constant (code, mode, val, target, source, subtargets, generate)     enum rtx_code code;     enum machine_mode mode;     HOST_WIDE_INT val;     rtx target;     rtx source;     int subtargets;     int generate;{  int can_add = 0;  int can_invert = 0;  int can_negate = 0;  int can_negate_initial = 0;  int can_shift = 0;  int i;  int num_bits_set = 0;  int set_sign_bit_copies = 0;  int clear_sign_bit_copies = 0;  int clear_zero_bit_copies = 0;  int set_zero_bit_copies = 0;  int insns = 0;  rtx new_src;  unsigned HOST_WIDE_INT temp1, temp2;  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;  /* find out which operations are safe for a given CODE.  Also do a quick     check for degenerate cases; these can occur when DImode operations     are split.  */  switch (code)    {    case SET:      can_invert = 1;      can_shift = 1;      can_negate = 1;      break;    case PLUS:      can_negate = 1;      can_negate_initial = 1;      break;    case IOR:      if (remainder == 0xffffffff)	{	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target,				GEN_INT (ARM_SIGN_EXTEND (val))));	  return 1;	}      if (remainder == 0)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      break;    case AND:      if (remainder == 0)	{	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx));	  return 1;	}      if (remainder == 0xffffffff)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      can_invert = 1;      break;    case XOR:      if (remainder == 0)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      if (remainder == 0xffffffff)	{	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target,				gen_rtx (NOT, mode, source)));	  return 1;	}      /* We don't know how to handle this yet below.  */      abort ();    case MINUS:      /* We treat MINUS as (val - source), since (source - val) is always	 passed as (source + (-val)).  */      if (remainder == 0)	{	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target,				gen_rtx (NEG, mode, source)));	  return 1;	}      if (const_ok_for_arm (val))	{	  if (generate)	    emit_insn (gen_rtx (SET, VOIDmode, target, 				gen_rtx (MINUS, mode, GEN_INT (val), source)));	  return 1;	}      can_negate = 1;      break;    default:      abort ();    }  /* If we can do it in one insn get out quickly */  if (const_ok_for_arm (val)      || (can_negate_initial && const_ok_for_arm (-val))      || (can_invert && const_ok_for_arm (~val)))    {      if (generate)	emit_insn (gen_rtx (SET, VOIDmode, target,			    (source ? gen_rtx (code, mode, source,					       GEN_INT (val))			     : GEN_INT (val))));      return 1;    }  /* Calculate a few attributes that may be useful for specific     optimizations. */  for (i = 31; i >= 0; i--)    {      if ((remainder & (1 << i)) == 0)	clear_sign_bit_copies++;      else	break;    }  for (i = 31; i >= 0; i--)    {      if ((remainder & (1 << i)) != 0)	set_sign_bit_copies++;      else	break;    }  for (i = 0; i <= 31; i++)    {      if ((remainder & (1 << i)) == 0)	clear_zero_bit_copies++;      else	break;    }  for (i = 0; i <= 31; i++)    {      if ((remainder & (1 << i)) != 0)	set_zero_bit_copies++;      else	break;    }  switch (code)    {    case SET:      /* See if we can do this by sign_extending a constant that is known	 to be negative.  This is a good, way of doing it, since the shift	 may well merge into a subsequent insn.  */      if (set_sign_bit_copies > 1)	{	  if (const_ok_for_arm	      (temp1 = ARM_SIGN_EXTEND (remainder 					<< (set_sign_bit_copies - 1))))	    {	      if (generate)		{		  new_src = subtargets ? gen_reg_rtx (mode) : target;		  emit_insn (gen_rtx (SET, VOIDmode, new_src, 				      GEN_INT (temp1)));		  emit_insn (gen_ashrsi3 (target, new_src, 					  GEN_INT (set_sign_bit_copies - 1)));		}	      return 2;	    }	  /* For an inverted constant, we will need to set the low bits,	     these will be shifted out of harm's way.  */	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;	  if (const_ok_for_arm (~temp1))	    {	      if (generate)		{		  new_src = subtargets ? gen_reg_rtx (mode) : target;		  emit_insn (gen_rtx (SET, VOIDmode, new_src,				      GEN_INT (temp1)));		  emit_insn (gen_ashrsi3 (target, new_src, 					  GEN_INT (set_sign_bit_copies - 1)));		}	      return 2;	    }	}      /* See if we can generate this by setting the bottom (or the top)	 16 bits, and then shifting these into the other half of the	 word.  We only look for the simplest cases, to do more would cost	 too much.  Be careful, however, not to generate this when the	 alternative would take fewer insns.  */      if (val & 0xffff0000)	{	  temp1 = remainder & 0xffff0000;	  temp2 = remainder & 0x0000ffff;	  /* Overlaps outside this range are best done using other methods. */	  for (i = 9; i < 24; i++)	    {	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)		  && ! const_ok_for_arm (temp2))		{		  insns = arm_gen_constant (code, mode, temp2,					    new_src = (subtargets						       ? gen_reg_rtx (mode)						       : target),					    source, subtargets, generate);		  source = new_src;		  if (generate)		    emit_insn (gen_rtx (SET, VOIDmode, target,					gen_rtx (IOR, mode,						 gen_rtx (ASHIFT, mode, source,							  GEN_INT (i)),						 source)));		  return insns + 1;		}	    }	  /* Don't duplicate cases already considered. */	  for (i = 17; i < 24; i++)	    {	      if (((temp1 | (temp1 >> i)) == remainder)		  && ! const_ok_for_arm (temp1))		{		  insns = arm_gen_constant (code, mode, temp1,					    new_src = (subtargets						       ? gen_reg_rtx (mode)						       : target),					    source, subtargets, generate);		  source = new_src;		  if (generate)		    emit_insn (gen_rtx (SET, VOIDmode, target,					gen_rtx (IOR, mode,						 gen_rtx (LSHIFTRT, mode,							  source, GEN_INT (i)),						 source)));		  return insns + 1;		}	    }	}      break;    case IOR:    case XOR:      /* If we have IOR or XOR, and the constant can be loaded in a	 single instruction, and we can find a temporary to put it in,	 then this can be done in two instructions instead of 3-4.  */      if (subtargets	  || (reload_completed && ! reg_mentioned_p (target, source)))	{	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val)))	    {	      if (generate)		{		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;		  emit_insn (gen_rtx (SET, VOIDmode, sub, GEN_INT (val)));		  emit_insn (gen_rtx (SET, VOIDmode, target, 				      gen_rtx (code, mode, source, sub)));		}	      return 2;	    }	}      if (code == XOR)	break;      if (set_sign_bit_copies > 8	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)	{	  if (generate)	    {	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;	      rtx shift = GEN_INT (set_sign_bit_copies);	      emit_insn (gen_rtx (SET, VOIDmode, sub,				  gen_rtx (NOT, mode, 					   gen_rtx (ASHIFT, mode, source, 						    shift))));	      emit_insn (gen_rtx (SET, VOIDmode, target,				  gen_rtx (NOT, mode,					   gen_rtx (LSHIFTRT, mode, sub,						    shift))));	    }	  return 2;	}      if (set_zero_bit_copies > 8	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)	{	  if (generate)	    {	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;	      rtx shift = GEN_INT (set_zero_bit_copies);	      emit_insn (gen_rtx (SET, VOIDmode, sub,				  gen_rtx (NOT, mode,					   gen_rtx (LSHIFTRT, mode, source,						    shift))));	      emit_insn (gen_rtx (SET, VOIDmode, target,				  gen_rtx (NOT, mode,					   gen_rtx (ASHIFT, mode, sub,						    shift))));	    }	  return 2;	}      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val)))	{	  if (generate)	    {	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_rtx (SET, VOIDmode, sub,				  gen_rtx (NOT, mode, source)));	      source = sub;	      if (subtargets)		sub = gen_reg_rtx (mode);	      emit_insn (gen_rtx (SET, VOIDmode, sub,				  gen_rtx (AND, mode, source, 					   GEN_INT (temp1))));	      emit_insn (gen_rtx (SET, VOIDmode, target,				  gen_rtx (NOT, mode, sub)));	    }	  return 3;	}      break;    case AND:      /* See if two shifts will do 2 or more insn's worth of work.  */      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)	{	  HOST_WIDE_INT shift_mask = ((0xffffffff 				       << (32 - clear_sign_bit_copies))				      & 0xffffffff);	  rtx new_source;	  rtx shift;	  if ((remainder | shift_mask) != 0xffffffff)	    {	      if (generate)		{		  new_source = subtargets ? gen_reg_rtx (mode) : target;		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,					    new_source, source, subtargets, 1);		  source = new_source;		}	      else		insns = arm_gen_constant (AND, mode, remainder | shift_mask,					  new_source, source, subtargets, 0);	    }	  if (generate)	    {	      shift = GEN_INT (clear_sign_bit_copies);	      new_source = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_ashlsi3 (new_source, source, shift));	      emit_insn (gen_lshrsi3 (target, new_source, shift));	    }	  return insns + 2;	}      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)	{	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;	  rtx new_source;	  rtx shift;	  	  if ((remainder | shift_mask) != 0xffffffff)	    {	      if (generate)		{		  new_source = subtargets ? gen_reg_rtx (mode) : target;		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,					    new_source, source, subtargets, 1);		  source = new_source;		}	      else		insns = arm_gen_constant (AND, mode, remainder | shift_mask,					  new_source, source, subtargets, 0);	    }	  if (generate)	    {	      shift = GEN_INT (clear_zero_bit_copies);	      new_source = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_lshrsi3 (new_source, source, shift));	      emit_insn (gen_ashlsi3 (target, new_source, shift));	    }	  return insns + 2;	}      break;    default:      break;    }  for (i = 0; i < 32; i++)    if (remainder & (1 << i))      num_bits_set++;  if (code == AND || (can_invert && num_bits_set > 16))    remainder = (~remainder) & 0xffffffff;  else if (code == PLUS && num_bits_set > 16)    remainder = (-remainder) & 0xffffffff;  else    {      can_invert = 0;      can_negate = 0;    }  /* Now try and find a way of doing the job in either two or three     instructions.     We start by looking for the largest block of zeros that are aligned on     a 2-bit boundary, we then fill up the temps, wrapping around to the     top of the word when we drop off the bottom.     In the worst case this code should produce no more than four insns. */  {    int best_start = 0;    int best_consecutive_zeros = 0;    for (i = 0; i < 32; i += 2)      {	int consecutive_zeros = 0;	if (! (remainder & (3 << i)))	  {	    while ((i < 32) && ! (remainder & (3 << i)))	      {		consecutive_zeros += 2;		i += 2;	      }	    if (consecutive_zeros > best_consecutive_zeros)	      {		best_consecutive_zeros = consecutive_zeros;		best_start = i - consecutive_zeros;	      }

⌨️ 快捷键说明

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