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

📄 i860.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* Return 1 if OP is an indexed memory reference of mode MODE.  */intindexed_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == MEM && GET_MODE (op) == mode	  && GET_CODE (XEXP (op, 0)) == PLUS	  && GET_MODE (XEXP (op, 0)) == SImode	  && register_operand (XEXP (XEXP (op, 0), 0), SImode)	  && register_operand (XEXP (XEXP (op, 0), 1), SImode));}/* Return 1 if OP is a suitable source operand for a load insn   with mode MODE.  */intload_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (memory_operand (op, mode) || indexed_operand (op, mode));}/* Return truth value of whether OP is a integer which fits the   range constraining immediate operands in add/subtract insns.  */intsmall_int (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of whether OP is a integer which fits the   range constraining immediate operands in logic insns.  */intlogic_int (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));}/* Test for a valid operand for a call instruction.   Don't allow the arg pointer register or virtual regs   since they may change into reg + const, which the patterns   can't handle yet.  */intcall_insn_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == MEM      && (CONSTANT_ADDRESS_P (XEXP (op, 0))	  || (GET_CODE (XEXP (op, 0)) == REG	      && XEXP (op, 0) != arg_pointer_rtx	      && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER		   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))    return 1;  return 0;}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */static char *singlemove_string (operands)     rtx *operands;{  if (GET_CODE (operands[0]) == MEM)    {      if (GET_CODE (operands[1]) != MEM)	if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))	  {	    if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		   && (cc_prev_status.flags & CC_HI_R31_ADJ)		   && cc_prev_status.mdep == XEXP (operands[0], 0)))	      {		CC_STATUS_INIT;	        output_asm_insn ("orh %h0,%?r0,%?r31", operands);	      }	    cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	    cc_status.mdep = XEXP (operands[0], 0);	    return "st.l %r1,%L0(%?r31)";	  }	else	  return "st.l %r1,%0";      else	abort ();#if 0	{	  rtx xoperands[2];	  cc_status.flags &= ~CC_F0_IS_0;	  xoperands[0] = gen_rtx (REG, SFmode, 32);	  xoperands[1] = operands[1];	  output_asm_insn (singlemove_string (xoperands), xoperands);	  xoperands[1] = xoperands[0];	  xoperands[0] = operands[0];	  output_asm_insn (singlemove_string (xoperands), xoperands);	  return "";	}#endif    }  if (GET_CODE (operands[1]) == MEM)    {      if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		 && (cc_prev_status.flags & CC_HI_R31_ADJ)		 && cc_prev_status.mdep == XEXP (operands[1], 0)))	    {	      CC_STATUS_INIT;	      output_asm_insn ("orh %h1,%?r0,%?r31", operands);	    }	  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	  cc_status.mdep = XEXP (operands[1], 0);	  return "ld.l %L1(%?r31),%0";	}      return "ld.l %m1,%0";    } if (GET_CODE (operands[1]) == CONST_INT)   {     if (operands[1] == const0_rtx)      return "mov %?r0,%0";     if((INTVAL (operands[1]) & 0xffff0000) == 0)      return "or %L1,%?r0,%0";     if((INTVAL (operands[1]) & 0xffff8000) == 0xffff8000)      return "adds %1,%?r0,%0";     if((INTVAL (operands[1]) & 0x0000ffff) == 0)      return "orh %H1,%?r0,%0";   }  return "mov %1,%0";}/* Output assembler code to perform a doubleword move insn   with operands OPERANDS.  */char *output_move_double (operands)     rtx *operands;{  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;  rtx latehalf[2];  rtx addreg0 = 0, addreg1 = 0;  int highest_first = 0;  int no_addreg1_decrement = 0;  /* First classify both operands.  */  if (REG_P (operands[0]))    optype0 = REGOP;  else if (offsettable_memref_p (operands[0]))    optype0 = OFFSOP;  else if (GET_CODE (operands[0]) == MEM)    optype0 = MEMOP;  else    optype0 = RNDOP;  if (REG_P (operands[1]))    optype1 = REGOP;  else if (CONSTANT_P (operands[1]))    optype1 = CNSTOP;  else if (offsettable_memref_p (operands[1]))    optype1 = OFFSOP;  else if (GET_CODE (operands[1]) == MEM)    optype1 = MEMOP;  else    optype1 = RNDOP;  /* Check for the cases that the operand constraints are not     supposed to allow to happen.  Abort if we get one,     because generating code for these cases is painful.  */  if (optype0 == RNDOP || optype1 == RNDOP)    abort ();  /* If an operand is an unoffsettable memory ref, find a register     we can increment temporarily to make it refer to the second word.  */  if (optype0 == MEMOP)    addreg0 = find_addr_reg (XEXP (operands[0], 0));  if (optype1 == MEMOP)    addreg1 = find_addr_reg (XEXP (operands[1], 0));/* ??? Perhaps in some cases move double words   if there is a spare pair of floating regs.  */  /* Ok, we can do one word at a time.     Normally we do the low-numbered word first,     but if either operand is autodecrementing then we     do the high-numbered word first.     In either case, set up in LATEHALF the operands to use     for the high-numbered word and in some cases alter the     operands in OPERANDS to be suitable for the low-numbered word.  */  if (optype0 == REGOP)    latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);  else if (optype0 == OFFSOP)    latehalf[0] = adj_offsettable_operand (operands[0], 4);  else    latehalf[0] = operands[0];  if (optype1 == REGOP)    latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);  else if (optype1 == OFFSOP)    latehalf[1] = adj_offsettable_operand (operands[1], 4);  else if (optype1 == CNSTOP)    {      if (GET_CODE (operands[1]) == CONST_DOUBLE)	split_double (operands[1], &operands[1], &latehalf[1]);      else if (CONSTANT_P (operands[1]))	latehalf[1] = const0_rtx;    }  else    latehalf[1] = operands[1];  /* If the first move would clobber the source of the second one,     do them in the other order.     RMS says "This happens only for registers;     such overlap can't happen in memory unless the user explicitly     sets it up, and that is an undefined circumstance."     but it happens on the sparc when loading parameter registers,     so I am going to define that circumstance, and make it work     as expected.  */  if (optype0 == REGOP && optype1 == REGOP      && REGNO (operands[0]) == REGNO (latehalf[1]))    {      CC_STATUS_PARTIAL_INIT;      /* Make any unoffsettable addresses point at high-numbered word.  */      if (addreg0)	output_asm_insn ("adds 0x4,%0,%0", &addreg0);      if (addreg1)	output_asm_insn ("adds 0x4,%0,%0", &addreg1);      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Undo the adds we just did.  */      if (addreg0)	output_asm_insn ("adds -0x4,%0,%0", &addreg0);      if (addreg1)	output_asm_insn ("adds -0x4,%0,%0", &addreg1);      /* Do low-numbered word.  */      return singlemove_string (operands);    }  else if (optype0 == REGOP && optype1 != REGOP	   && reg_overlap_mentioned_p (operands[0], operands[1]))    {      /* If both halves of dest are used in the src memory address,	 add the two regs and put them in the low reg (operands[0]).	 Then it works to load latehalf first.  */      if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))	  && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	{	  rtx xops[2];	  xops[0] = latehalf[0];	  xops[1] = operands[0];	  output_asm_insn ("adds %1,%0,%1", xops);	  operands[1] = gen_rtx (MEM, DImode, operands[0]);	  latehalf[1] = adj_offsettable_operand (operands[1], 4);	  addreg1 = 0;	  highest_first = 1;	}      /* Only one register in the dest is used in the src memory address,	 and this is the first register of the dest, so we want to do	 the late half first here also.  */      else if (! reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	highest_first = 1;      /* Only one register in the dest is used in the src memory address,	 and this is the second register of the dest, so we want to do	 the late half last.  If addreg1 is set, and addreg1 is the same	 register as latehalf, then we must suppress the trailing decrement,	 because it would clobber the value just loaded.  */      else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0]))	no_addreg1_decrement = 1;    }  /* Normal case: do the two words, low-numbered first.     Overlap case (highest_first set): do high-numbered word first.  */  if (! highest_first)    output_asm_insn (singlemove_string (operands), operands);  CC_STATUS_PARTIAL_INIT;  /* Make any unoffsettable addresses point at high-numbered word.  */  if (addreg0)    output_asm_insn ("adds 0x4,%0,%0", &addreg0);  if (addreg1)    output_asm_insn ("adds 0x4,%0,%0", &addreg1);  /* Do that word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    output_asm_insn ("adds -0x4,%0,%0", &addreg0);  if (addreg1 && !no_addreg1_decrement)    output_asm_insn ("adds -0x4,%0,%0", &addreg1);  if (highest_first)    output_asm_insn (singlemove_string (operands), operands);  return "";}char *output_fp_move_double (operands)     rtx *operands;{  /* If the source operand is any sort of zero, use f0 instead.  */  if (operands[1] == CONST0_RTX (GET_MODE (operands[1])))    operands[1] = gen_rtx (REG, DFmode, F0_REGNUM);  if (FP_REG_P (operands[0]))    {      if (FP_REG_P (operands[1]))	return "fmov.dd %1,%0";      if (GET_CODE (operands[1]) == REG)	{	  output_asm_insn ("ixfr %1,%0", operands);	  operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);	  operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);	  return "ixfr %1,%0";	}      if (operands[1] == CONST0_RTX (DFmode))	return "fmov.dd f0,%0";      if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		 && (cc_prev_status.flags & CC_HI_R31_ADJ)		 && cc_prev_status.mdep == XEXP (operands[1], 0)))	    {	      CC_STATUS_INIT;	      output_asm_insn ("orh %h1,%?r0,%?r31", operands);	    }	  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	  cc_status.mdep = XEXP (operands[1], 0);	  return "fld.d %L1(%?r31),%0";	}      return "fld.d %1,%0";    }  else if (FP_REG_P (operands[1]))    {      if (GET_CODE (operands[0]) == REG)	{	  output_asm_insn ("fxfr %1,%0", operands);	  operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);	  operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);	  return "fxfr %1,%0";	}      if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		 && (cc_prev_status.flags & CC_HI_R31_ADJ)		 && cc_prev_status.mdep == XEXP (operands[0], 0)))	    {	      CC_STATUS_INIT;	      output_asm_insn ("orh %h0,%?r0,%?r31", operands);	    }	  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	  cc_status.mdep = XEXP (operands[0], 0);	  return "fst.d %1,%L0(%?r31)";	}      return "fst.d %1,%0";    }  else    abort ();  /* NOTREACHED */  return NULL;}/* Return a REG that occurs in ADDR with coefficient 1.   ADDR can be effectively incremented by incrementing REG.  */static rtxfind_addr_reg (addr)     rtx addr;{  while (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG)	addr = XEXP (addr, 0);      else if (GET_CODE (XEXP (addr, 1)) == REG)	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 0)))	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 1)))	addr = XEXP (addr, 0);      else	abort ();    }  if (GET_CODE (addr) == REG)    return addr;  abort ();  /* NOTREACHED */  return NULL;}/* Return a template for a load instruction with mode MODE and   arguments from the string ARGS.   This string is in static storage.   */static char *load_opcode (mode, args, reg)

⌨️ 快捷键说明

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