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

📄 sh.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
	    emit_insn (gen_addsi3 (op1, op1, force_reg (SImode, opc)));	  operands[1] = op1;	}    }  return 0;}/* Prepare the operands for an scc instruction; make sure that the   compare has been done.  */rtxprepare_scc_operands (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.  */      gcc_unreachable ();    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_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))    sh_compare_op1 = force_reg (mode, sh_compare_op1);  if ((TARGET_SH4 || TARGET_SH2A) && 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_fmt_ee (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_fmt_ee (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 (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_SH2E && 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_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))	sh_compare_op1 = force_reg (mode, sh_compare_op1);    }  if (TARGET_SH2E && 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_fmt_ee (code, SImode,					sh_compare_op0, sh_compare_op1));  if ((TARGET_SH4 || TARGET_SH2A) && 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 (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);      switch (GET_CODE (inside))	{	case REG:	  ptrreg = REGNO (inside);	  break;	case SUBREG:	  ptrreg = subreg_regno (inside);	  break;	case 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	     requires r0 for the other operand, which is not currently	     supported, so we can't use the 'o' constraint.	     Thus we must check for and handle r0+REG addresses here.	     We punt for now, since this is likely very rare.  */	  gcc_assert (GET_CODE (XEXP (inside, 1)) != REG);	  break;	  	case LABEL_REF:	  return "mov.l	%1,%0\n\tmov.l	%1+4,%T0";	case POST_INC:	  return "mov.l	%1,%0\n\tmov.l	%1,%T0";	default:	  gcc_unreachable ();	}      /* Work out the safe way to copy.  Copy into the second half first.  */      if (dreg == ptrreg)	return "mov.l	%T1,%T0\n\tmov.l	%1,%0";    }  return "mov.l	%1,%0\n\tmov.l	%T1,%T0";}/* Print an instruction which would have gone into a delay slot after   another instruction, but couldn't because the other instruction expanded   into a sequence where putting the slot insn at the end wouldn't work.  */static voidprint_slot (rtx insn){  final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 1, NULL);  INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;}const char *output_far_jump (rtx insn, rtx op){  struct { rtx lab, reg, op; } this;  rtx braf_base_lab = NULL_RTX;  const char *jump;  int far;  int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));  rtx prev;  this.lab = gen_label_rtx ();  if (TARGET_SH2      && offset >= -32764      && offset - get_attr_length (insn) <= 32766)    {      far = 0;      jump = "mov.w	%O0,%1; braf	%1";    }  else    {      far = 1;      if (flag_pic)	{	  if (TARGET_SH2)	    jump = "mov.l	%O0,%1; braf	%1";	  else	    jump = "mov.l	r0,@-r15; mova	%O0,r0; mov.l	@r0,%1; add	r0,%1; mov.l	@r15+,r0; jmp	@%1";	}      else	jump = "mov.l	%O0,%1; jmp	@%1";    }  /* If we have a scratch register available, use it.  */  if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN      && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)    {      this.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));      if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2)	jump = "mov.l	r1,@-r15; mova	%O0,r0; mov.l	@r0,r1; add	r1,r0; mov.l	@r15+,r1; jmp	@%1";      output_asm_insn (jump, &this.lab);      if (dbr_sequence_length ())	print_slot (final_sequence);      else	output_asm_insn ("nop", 0);    }  else    {      /* Output the delay slot insn first if any.  */      if (dbr_sequence_length ())	print_slot (final_sequence);      this.reg = gen_rtx_REG (SImode, 13);      /* We must keep the stack aligned to 8-byte boundaries on SH5.	 Fortunately, MACL is fixed and call-clobbered, and we never	 need its value across jumps, so save r13 in it instead of in	 the stack.  */      if (TARGET_SH5)	output_asm_insn ("lds	r13, macl", 0);      else	output_asm_insn ("mov.l	r13,@-r15", 0);      output_asm_insn (jump, &this.lab);      if (TARGET_SH5)	output_asm_insn ("sts	macl, r13", 0);      else	output_asm_insn ("mov.l	@r15+,r13", 0);    }  if (far && flag_pic && TARGET_SH2)    {      braf_base_lab = gen_label_rtx ();      (*targetm.asm_out.internal_label) (asm_out_file, "L",				 CODE_LABEL_NUMBER (braf_base_lab));    }  if (far)    output_asm_insn (".align	2", 0);  (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab));  this.op = op;  if (far && flag_pic)    {      if (TARGET_SH2)	this.lab = braf_base_lab;      output_asm_insn (".long	%O2-%O0", &this.lab);    }  else    output_asm_insn (far ? ".long	%O2" : ".word %O2-%O0", &this.lab);  return "";}/* Local label counter, used for constants in the pool and inside   pattern branches.  */static int lf = 100;/* Output code for ordinary branches.  */const char *output_branch (int logic, rtx insn, rtx *operands){  switch (get_attr_length (insn))    {    case 6:      /* This can happen if filling the delay slot has caused a forward	 branch to exceed its range (we could reverse it, but only	 when we know we won't overextend other branches; this should	 best be handled by relaxation).	 It can also happen when other condbranches hoist delay slot insn	 from their destination, thus leading to code size increase.	 But the branch will still be in the range -4092..+4098 bytes.  */      if (! TARGET_RELAX)	{	  int label = lf++;	  /* The call to print_slot will clobber the operands.  */	  rtx op0 = operands[0];	  /* If the instruction in the delay slot is annulled (true), then	     there is no delay slot where we can put it now.  The only safe	     place for it is after the label.  final will do that by default.  */	  if (final_sequence	      && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))	      && get_attr_length (XVECEXP (final_sequence, 0, 1)))	    {	      asm_fprintf (asm_out_file, "\tb%s%ss\t%LLF%d\n", logic ? "f" : "t",	                   ASSEMBLER_DIALECT ? "/" : ".", label);	      print_slot (final_sequence);	    }	  else	    asm_fprintf (asm_out_file, "\tb%s\t%LLF%d\n", logic ? "f" : "t", label);	  output_asm_insn ("bra\t%l0", &op0);	  fprintf (asm_out_file, "\tnop\n");	  (*targetm.asm_out.internal_label) (asm_out_file, "LF", label);	  return "";	}      /* When relaxing, handle this like a short branch.  The linker	 will fix it up if it still doesn't fit after relaxation.  */    case 2:      return logic ? "bt%.\t%l0" : "bf%.\t%l0";      /* These are for SH2e, in which we have to account for the	 extra nop because of the hardware bug in annulled branches.  */    case 8:      if (! TARGET_RELAX)	{	  int label = lf++;	  gcc_assert (!final_sequence		      || !(INSN_ANNULLED_BRANCH_P			   (XVECEXP (final_sequence, 0, 0))));	  asm_fprintf (asm_out_file, "b%s%ss\t%LLF%d\n",		       logic ? "f" : "t",		       ASSEMBLER_DIALECT ? "/" : ".", label);	  fprintf (asm_out_file, "\tnop\n");	  output_asm_insn ("bra\t%l0", operands);	  fprintf (asm_out_file, "\tnop\n");	  (*targetm.asm_out.internal_label) (asm_out_file, "LF", label);	  return "";	}      /* When relaxing, fall through.  */    case 4:      {	char buffer[10];	sprintf (buffer, "b%s%ss\t%%l0",		 logic ? "t" : "f",		 ASSEMBLER_DIALECT ? "/" : ".");	output_asm_insn (buffer, &operands[0]);	return "nop";      }    default:      /* There should be no longer branches now - that would	 indicate that something has destroyed the branches set	 up in machine_dependent_reorg.  */      gcc_unreachable ();    }}const char *output_branchy_insn (enum rtx_code code, const char *template,		     rtx insn, rtx *operands){  rtx next_insn = NEXT_INSN (insn);  if (next_insn && GET_CODE (next_insn) == JUMP_INSN && condjump_p (next_insn))    {      rtx src = SET_SRC (PATTERN (next_insn));      if (GET_CODE (src) == IF_THEN_ELSE && GET_CODE (XEXP (src, 0)) != code)	{	  /* Following branch not taken */	  operands[9] = gen_label_rtx ();	  emit_label_after (operands[9], next_insn);	  INSN_ADDRESSES_NEW (operands[9],			      INSN_ADDRESSES (INSN_UID (next_insn))			      + get_attr_length (next_insn));	  return template;	}      else	{	  int offset = (branch_dest (next_insn)			- INSN_ADDRESSES (INSN_UID (next_insn)) + 4);	  if (offset >= -252 && offset <= 258)	    {	      if (GET_CODE (src) == IF_THEN_ELSE)		/* branch_true */		src = XEXP (src, 1);	      operands[9] = src;	      return template;	    }	}    }  operands[9] = gen_label_rtx ();  emit_label_after (operands[9], insn);  INSN_ADDRESSES_NEW (operands[9],		      INSN_ADDRESSES (INSN_UID (insn))		      + get_attr_length (insn));  return template;}const char *output_ieee_ccmpeq (rtx insn, rtx *operands)

⌨️ 快捷键说明

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