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

📄 sh.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
      if (x == CONST0_RTX (GET_MODE (x)))	{	  fprintf ((stream), "r63");	  break;	}      goto default_output;    case 'u':      if (GET_CODE (x) == CONST_INT)	{	  fprintf ((stream), "%u", (unsigned) INTVAL (x) & (0x10000 - 1));	  break;	}      /* Fall through.  */    default_output:    default:      switch (GET_CODE (x))	{	  /* FIXME: We need this on SHmedia32 because reload generates	     some sign-extended HI or QI loads into DImode registers	     but, because Pmode is SImode, the address ends up with a	     subreg:SI of the DImode register.  Maybe reload should be	     fixed so as to apply alter_subreg to such loads?  */	case SUBREG:	  if (SUBREG_BYTE (x) != 0	      || GET_CODE (SUBREG_REG (x)) != REG)	    abort ();	  x = SUBREG_REG (x);	  /* Fall through.  */	case REG:	  if (FP_REGISTER_P (REGNO (x))	      && GET_MODE (x) == V16SFmode)	    fprintf ((stream), "mtrx%s", reg_names[REGNO (x)] + 2);	  else if (FP_REGISTER_P (REGNO (x))		   && GET_MODE (x) == V4SFmode)	    fprintf ((stream), "fv%s", reg_names[REGNO (x)] + 2);	  else if (GET_CODE (x) == REG		   && GET_MODE (x) == V2SFmode)	    fprintf ((stream), "fp%s", reg_names[REGNO (x)] + 2);	  else if (FP_REGISTER_P (REGNO (x))		   && GET_MODE_SIZE (GET_MODE (x)) > 4)	    fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1);	  else	    fputs (reg_names[REGNO (x)], (stream));	  break;	case MEM:	  output_address (XEXP (x, 0));	  break;	  	case CONST:	  if (TARGET_SHMEDIA	      && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND	      && GET_MODE (XEXP (x, 0)) == DImode	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == TRUNCATE	      && GET_MODE (XEXP (XEXP (x, 0), 0)) == HImode)	    {	      rtx val = XEXP (XEXP (XEXP (x, 0), 0), 0);	      fputc ('(', stream);	      if (GET_CODE (val) == ASHIFTRT)		{		  fputc ('(', stream);		  if (GET_CODE (XEXP (val, 0)) == CONST)		    fputc ('(', stream);		  output_addr_const (stream, XEXP (val, 0));		  if (GET_CODE (XEXP (val, 0)) == CONST)		    fputc (')', stream);		  fputs (" >> ", stream);		  output_addr_const (stream, XEXP (val, 1));		  fputc (')', stream);		}	      else		{		  if (GET_CODE (val) == CONST)		    fputc ('(', stream);		  output_addr_const (stream, val);		  if (GET_CODE (val) == CONST)		    fputc (')', stream);		}	      fputs (" & 65535)", stream);	      break;	    }	  /* Fall through.  */	default:	  if (TARGET_SH1)	    fputc ('#', stream);	  output_addr_const (stream, x);	  break;	}      break;    }}/* Like force_operand, but guarantees that VALUE ends up in TARGET.  */static voidforce_into (value, target)     rtx value, target;{  value = force_operand (value, target);  if (! rtx_equal_p (value, target))    emit_insn (gen_move_insn (target, value));}/* Emit code to perform a block move.  Choose the best method.   OPERANDS[0] is the destination.   OPERANDS[1] is the source.   OPERANDS[2] is the size.   OPERANDS[3] is the alignment safe to use.  */intexpand_block_move (operands)     rtx *operands;{  int align = INTVAL (operands[3]);  int constp = (GET_CODE (operands[2]) == CONST_INT);  int bytes = (constp ? INTVAL (operands[2]) : 0);  /* If it isn't a constant number of bytes, or if it doesn't have 4 byte     alignment, or if it isn't a multiple of 4 bytes, then fail.  */  if (! constp || align < 4 || (bytes % 4 != 0))    return 0;  if (TARGET_HARD_SH4)    {      if (bytes < 12)	return 0;      else if (bytes == 12)	{	  tree entry_name;	  rtx sym;	  rtx func_addr_rtx;	  rtx r4 = gen_rtx (REG, SImode, 4);	  rtx r5 = gen_rtx (REG, SImode, 5);	  entry_name = get_identifier ("__movstrSI12_i4");	  sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name));	  func_addr_rtx = copy_to_mode_reg (Pmode, sym);	  force_into (XEXP (operands[0], 0), r4);	  force_into (XEXP (operands[1], 0), r5);	  emit_insn (gen_block_move_real_i4 (func_addr_rtx));	  return 1;	}      else if (! TARGET_SMALLCODE)	{	  tree entry_name;	  rtx sym;	  rtx func_addr_rtx;	  int dwords;	  rtx r4 = gen_rtx (REG, SImode, 4);	  rtx r5 = gen_rtx (REG, SImode, 5);	  rtx r6 = gen_rtx (REG, SImode, 6);	  entry_name = get_identifier (bytes & 4				       ? "__movstr_i4_odd"				       : "__movstr_i4_even");	  sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name));	  func_addr_rtx = copy_to_mode_reg (Pmode, sym);	  force_into (XEXP (operands[0], 0), r4);	  force_into (XEXP (operands[1], 0), r5);	  dwords = bytes >> 3;	  emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1)));	  emit_insn (gen_block_lump_real_i4 (func_addr_rtx));	  return 1;	}      else	return 0;    }  if (bytes < 64)    {      char entry[30];      tree entry_name;      rtx sym;      rtx func_addr_rtx;      rtx r4 = gen_rtx_REG (SImode, 4);      rtx r5 = gen_rtx_REG (SImode, 5);      sprintf (entry, "__movstrSI%d", bytes);      entry_name = get_identifier (entry);      sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name));      func_addr_rtx = copy_to_mode_reg (Pmode, sym);      force_into (XEXP (operands[0], 0), r4);      force_into (XEXP (operands[1], 0), r5);      emit_insn (gen_block_move_real (func_addr_rtx));      return 1;    }  /* This is the same number of bytes as a memcpy call, but to a different     less common function name, so this will occasionally use more space.  */  if (! TARGET_SMALLCODE)    {      tree entry_name;      rtx sym;      rtx func_addr_rtx;      int final_switch, while_loop;      rtx r4 = gen_rtx_REG (SImode, 4);      rtx r5 = gen_rtx_REG (SImode, 5);      rtx r6 = gen_rtx_REG (SImode, 6);      entry_name = get_identifier ("__movstr");      sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name));      func_addr_rtx = copy_to_mode_reg (Pmode, sym);      force_into (XEXP (operands[0], 0), r4);      force_into (XEXP (operands[1], 0), r5);      /* r6 controls the size of the move.  16 is decremented from it	 for each 64 bytes moved.  Then the negative bit left over is used	 as an index into a list of move instructions.  e.g., a 72 byte move	 would be set up with size(r6) = 14, for one iteration through the	 big while loop, and a switch of -2 for the last part.  */      final_switch = 16 - ((bytes / 4) % 16);      while_loop = ((bytes / 4) / 16 - 1) * 16;      emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));      emit_insn (gen_block_lump_real (func_addr_rtx));      return 1;    }  return 0;}/* Prepare operands for a move define_expand; specifically, one of the   operands must be in a register.  */intprepare_move_operands (operands, mode)     rtx operands[];     enum machine_mode mode;{  if ((mode == SImode || mode == DImode) && flag_pic)    {      rtx temp;      if (SYMBOLIC_CONST_P (operands[1]))	{	  if (GET_CODE (operands[0]) == MEM)	    operands[1] = force_reg (Pmode, operands[1]);	  else if (TARGET_SHMEDIA		   && GET_CODE (operands[1]) == LABEL_REF		   && target_reg_operand (operands[0], mode))	    /* It's ok.  */;	  else	    {	      temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);	      operands[1] = legitimize_pic_address (operands[1], mode, temp);	    }	}      else if (GET_CODE (operands[1]) == CONST	       && GET_CODE (XEXP (operands[1], 0)) == PLUS	       && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))	{	  temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);	  temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),					 mode, temp);	  operands[1] = expand_binop (mode, add_optab, temp,				      XEXP (XEXP (operands[1], 0), 1),				      no_new_pseudos ? temp				      : gen_reg_rtx (Pmode),				      0, OPTAB_LIB_WIDEN);	}    }  if (! reload_in_progress && ! reload_completed)    {      /* Copy the source to a register if both operands aren't registers.  */      if (! register_operand (operands[0], mode)	  && ! sh_register_operand (operands[1], mode))	operands[1] = copy_to_mode_reg (mode, operands[1]);      /* This case can happen while generating code to move the result	 of a library call to the target.  Reject `st r0,@(rX,rY)' because	 reload will fail to find a spill register for rX, since r0 is already	 being used for the source.  */      else if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 0	       && GET_CODE (operands[0]) == MEM	       && GET_CODE (XEXP (operands[0], 0)) == PLUS	       && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG)	operands[1] = copy_to_mode_reg (mode, operands[1]);    }  return 0;}/* Prepare the operands for an scc instruction; make sure that the   compare has been done.  */rtxprepare_scc_operands (code)     enum rtx_code code;{  rtx t_reg = gen_rtx_REG (SImode, T_REG);  enum rtx_code oldcode = code;  enum machine_mode mode;  /* First need a compare insn.  */  switch (code)    {    case NE:      /* It isn't possible to handle this case.  */      abort ();    case LT:      code = GT;      break;    case LE:      code = GE;      break;    case LTU:      code = GTU;      break;    case LEU:      code = GEU;      break;    default:      break;    }  if (code != oldcode)    {      rtx tmp = sh_compare_op0;      sh_compare_op0 = sh_compare_op1;      sh_compare_op1 = tmp;    }  mode = GET_MODE (sh_compare_op0);  if (mode == VOIDmode)    mode = GET_MODE (sh_compare_op1);  sh_compare_op0 = force_reg (mode, sh_compare_op0);  if ((code != EQ && code != NE       && (sh_compare_op1 != const0_rtx	   || code == GTU  || code == GEU || code == LTU || code == LEU))      || (mode == DImode && sh_compare_op1 != const0_rtx)      || (TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT))    sh_compare_op1 = force_reg (mode, sh_compare_op1);  if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)    (mode == SFmode ? emit_sf_insn : emit_df_insn)     (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,		gen_rtx (SET, VOIDmode, t_reg,			 gen_rtx (code, SImode,				  sh_compare_op0, sh_compare_op1)),		gen_rtx (USE, VOIDmode, get_fpscr_rtx ()))));  else    emit_insn (gen_rtx (SET, VOIDmode, t_reg,			gen_rtx (code, SImode, sh_compare_op0,				 sh_compare_op1)));  return t_reg;}/* Called from the md file, set up the operands of a compare instruction.  */voidfrom_compare (operands, code)     rtx *operands;     int code;{  enum machine_mode mode = GET_MODE (sh_compare_op0);  rtx insn;  if (mode == VOIDmode)    mode = GET_MODE (sh_compare_op1);  if (code != EQ      || mode == DImode      || (TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT))    {      /* Force args into regs, since we can't use constants here.  */      sh_compare_op0 = force_reg (mode, sh_compare_op0);      if (sh_compare_op1 != const0_rtx	  || code == GTU  || code == GEU	  || (TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT))	sh_compare_op1 = force_reg (mode, sh_compare_op1);    }  if (TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT && code == GE)    {      from_compare (operands, GT);      insn = gen_ieee_ccmpeqsf_t (sh_compare_op0, sh_compare_op1);    }  else    insn = gen_rtx_SET (VOIDmode,			gen_rtx_REG (SImode, T_REG),			gen_rtx (code, SImode, sh_compare_op0,				 sh_compare_op1));  if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)    {      insn = gen_rtx (PARALLEL, VOIDmode,		      gen_rtvec (2, insn,				 gen_rtx (USE, VOIDmode, get_fpscr_rtx ())));      (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);    }  else    emit_insn (insn);}/* Functions to output assembly code.  *//* Return a sequence of instructions to perform DI or DF move.   Since the SH cannot move a DI or DF in one instruction, we have   to take care when we see overlapping source and dest registers.  */const char *output_movedouble (insn, operands, mode)     rtx insn ATTRIBUTE_UNUSED;     rtx operands[];     enum machine_mode mode;{  rtx dst = operands[0];  rtx src = operands[1];  if (GET_CODE (dst) == MEM      && GET_CODE (XEXP (dst, 0)) == PRE_DEC)    return "mov.l	%T1,%0\n\tmov.l	%1,%0";  if (register_operand (dst, mode)      && register_operand (src, mode))    {      if (REGNO (src) == MACH_REG)	return "sts	mach,%S0\n\tsts	macl,%R0";      /* When mov.d r1,r2 do r2->r3 then r1->r2;         when mov.d r1,r0 do r1->r0 then r2->r1.  */      if (REGNO (src) + 1 == REGNO (dst))	return "mov	%T1,%T0\n\tmov	%1,%0";      else	return "mov	%1,%0\n\tmov	%T1,%T0";    }  else if (GET_CODE (src) == CONST_INT)    {      if (INTVAL (src) < 0)	output_asm_insn ("mov	#-1,%S0", operands);      else	output_asm_insn ("mov	#0,%S0", operands);      return "mov	%1,%R0";    }  else if (GET_CODE (src) == MEM)    {      int ptrreg = -1;      int dreg = REGNO (dst);      rtx inside = XEXP (src, 0);      if (GET_CODE (inside) == REG)	ptrreg = REGNO (inside);      else if (GET_CODE (inside) == SUBREG)	ptrreg = subreg_regno (inside);      else if (GET_CODE (inside) == PLUS)	{	  ptrreg = REGNO (XEXP (inside, 0));	  /* ??? A r0+REG address shouldn't be possible here, because it isn't	     an offsettable address.  Unfortunately, offsettable addresses use	     QImode to check the offset, and a QImode offsettable address

⌨️ 快捷键说明

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