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

📄 out-i860.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Return 1 if OP is a valid first operand for either a logical insn   or an add insn of mode MODE.  */intcompare_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));}/* Return truth value of whether OP can be used as an operand   of a bte insn.  */intbte_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && (unsigned) INTVAL (op) < 0x20));}/* 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));}/* 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)))	      output_asm_insn ("orh ha%%%m0,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,l%%%m0(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)))	    output_asm_insn ("orh ha%%%m1,r0,r31", operands);	  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	  cc_status.mdep = XEXP (operands[1], 0);	  return "ld.l l%%%m1(r31),%0";	}      return "ld.l %1,%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;  /* 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])	   || GET_CODE (operands[1]) == CONST_DOUBLE)    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 (CONSTANT_P (operands[1]))	latehalf[1] = const0_rtx;      else if (GET_CODE (operands[1]) == CONST_DOUBLE)	{	  latehalf[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_HIGH (operands[1]));	  operands[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_LOW (operands[1]));	}    }  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]))    {      /* 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]))    {      /* Do the late half first.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Then clobber.  */      return singlemove_string (operands);    }  /* Normal case: do the two words, low-numbered first.  */  output_asm_insn (singlemove_string (operands), operands);  /* 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);  return "";}static char *output_fp_move_double (operands)     rtx *operands;{  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] == dconst0_rtx)	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)))	    output_asm_insn ("orh ha%%%m1,r0,r31", operands);	  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	  cc_status.mdep = XEXP (operands[1], 0);	  return "fld.d l%%%m1(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)))	    output_asm_insn ("orh ha%%%m0,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,l%%%m0(r31)";	}      return "fst.d %1,%0";    }  else abort ();}/* 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 ();}/* 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)     enum machine_mode mode;     char *args;     rtx reg;{  static char buf[30];  char *opcode;  switch (mode)    {    case QImode:      opcode = "ld.b";      break;    case HImode:      opcode = "ld.s";      break;    case SImode:    case SFmode:      if (FP_REG_P (reg))	opcode = "fld.l";      else	opcode = "ld.l";      break;    case DImode:      if (!FP_REG_P (reg))	abort ();    case DFmode:      opcode = "fld.d";      break;    default:      abort ();    }  sprintf (buf, "%s %s", opcode, args);  return buf;}/* Return a template for a store instruction with mode MODE and   arguments from the string ARGS.   This string is in static storage.   */static char *store_opcode (mode, args, reg)     enum machine_mode mode;     char *args;     rtx reg;{  static char buf[30];  char *opcode;  switch (mode)    {    case QImode:      opcode = "st.b";      break;    case HImode:      opcode = "st.s";      break;    case SImode:    case SFmode:      if (FP_REG_P (reg))	opcode = "fst.l";      else	opcode = "st.l";      break;    case DImode:      if (!FP_REG_P (reg))	abort ();    case DFmode:      opcode = "fst.d";      break;    default:      abort ();    }  sprintf (buf, "%s %s", opcode, args);  return buf;}/* Output a store-in-memory whose operands are OPERANDS[0,1].   OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.   This function returns a template for an insn.   This is in static storage.   It may also output some insns directly.   It may alter the values of operands[0] and operands[1].  */char *output_store (operands)     rtx *operands;{  enum machine_mode mode = GET_MODE (operands[0]);  rtx address = XEXP (operands[0], 0);  char *string;  cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;  cc_status.mdep = address;  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)	 && (cc_prev_status.flags & CC_HI_R31_ADJ)	 && address == cc_prev_status.mdep))    {      output_asm_insn ("orh ha%%%m0,r0,r31", operands);      cc_prev_status.mdep = address;    }  /* Store zero in two parts when appropriate.  */  if (mode == DFmode && operands[1] == dconst0_rtx)    return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);  /* Code below isn't smart enough to move a doubleword in two parts,     so use output_move_double to do that in the cases that require it.  */  if ((mode == DImode || mode == DFmode)      && ! FP_REG_P (operands[1]))    return output_move_double (operands);  return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);}/* Output a load-from-memory whose operands are OPERANDS[0,1].   OPERANDS[0] is a reg, and OPERANDS[1] is a mem.   This function returns a template for an insn.   This is in static storage.   It may also output some insns directly.   It may alter the values of operands[0] and operands[1].  */char *output_load (operands)

⌨️ 快捷键说明

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