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

📄 sparc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
					      pc_rtx))));      return 1;    }  /* Now have insn-emit do whatever it normally does.  */  return 0;}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */char *singlemove_string (operands)     rtx *operands;{  if (GET_CODE (operands[0]) == MEM)    {      if (GET_CODE (operands[1]) != MEM)	return "st %r1,%0";      else	abort ();    }  else if (GET_CODE (operands[1]) == MEM)    return "ld %1,%0";  else if (GET_CODE (operands[1]) == CONST_DOUBLE)    {      int i;      union real_extract u;      union float_extract { float f; int i; } v;      /* Must be SFmode, otherwise this doesn't make sense.  */      if (GET_MODE (operands[1]) != SFmode)	abort ();      bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u);      v.f = REAL_VALUE_TRUNCATE (SFmode, u.d);      i = v.i;      operands[1] = gen_rtx (CONST_INT, VOIDmode, i);      if (CONST_OK_FOR_LETTER_P (i, 'I'))	return "mov %1,%0";      else if ((i & 0x000003FF) != 0)	return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";      else	return "sethi %%hi(%a1),%0";    }  else if (GET_CODE (operands[1]) == CONST_INT	   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))    {      int i = INTVAL (operands[1]);      /* If all low order 10 bits are clear, then we only need a single	 sethi insn to load the constant.  */      if ((i & 0x000003FF) != 0)	return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";      else	return "sethi %%hi(%a1),%0";    }  /* Operand 1 must be a register, or a 'I' type CONST_INT.  */  return "mov %1,%0";}/* Return non-zero if it is OK to assume that the given memory operand is   aligned at least to a 8-byte boundary.  This should only be called   for memory accesses whose size is 8 bytes or larger.  */intmem_aligned_8 (mem)     register rtx mem;{  register rtx addr;  register rtx base;  register rtx offset;  if (GET_CODE (mem) != MEM)    return 0;	/* It's gotta be a MEM! */  addr = XEXP (mem, 0);#if 1  /* Now that all misaligned double parms are copied on function entry,     we can assume any 64-bit object is 64-bit aligned.  */  /* See what register we use in the address.  */  base = 0;  if (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG	  && GET_CODE (XEXP (addr, 1)) == CONST_INT)	{	  base = XEXP (addr, 0);	  offset = XEXP (addr, 1);	}    }  else if (GET_CODE (addr) == REG)    {      base = addr;      offset = const0_rtx;    }  /* If it's the stack or frame pointer, check offset alignment.     We can have improper alignment in the function entry code.  */  if (base      && (REGNO (base) == FRAME_POINTER_REGNUM	  || REGNO (base) == STACK_POINTER_REGNUM))    {      if ((INTVAL (offset) & 0x7) == 0)	return 1;    }  else    /* Anything else, we know is properly aligned.  */    return 1;#else  /* If the operand is known to have been allocated in static storage, then     it must be aligned.  */  if (CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM)    return 1;  base = 0;  if (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG          && GET_CODE (XEXP (addr, 1)) == CONST_INT)        {          base = XEXP (addr, 0);          offset = XEXP (addr, 1);        }    }  else if (GET_CODE (addr) == REG)    {      base = addr;      offset = const0_rtx;    }  /* Trust round enough offsets from the stack or frame pointer.     If TARGET_HOPE_ALIGN, trust round enough offset from any register.     If it is obviously unaligned, don't ever return true.  */  if (base      && (REGNO (base) == FRAME_POINTER_REGNUM          || REGNO (base) == STACK_POINTER_REGNUM	  || TARGET_HOPE_ALIGN))    {      if ((INTVAL (offset) & 0x7) == 0)	return 1;    }  /* Otherwise, we can assume that an access is aligned if it is to an     aggregate.  Also, if TARGET_HOPE_ALIGN, then assume everything that isn't     obviously unaligned is aligned.  */  else if (MEM_IN_STRUCT_P (mem) || TARGET_HOPE_ALIGN)    return 1;#endif  /* An obviously unaligned address.  */  return 0;}enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };/* Output assembler code to perform a doubleword move insn   with operands OPERANDS.  This is very similar to the following   output_move_quad function.  */char *output_move_double (operands)     rtx *operands;{  register rtx op0 = operands[0];  register rtx op1 = operands[1];  register enum optype optype0;  register enum optype optype1;  rtx latehalf[2];  rtx addreg0 = 0;  rtx addreg1 = 0;  /* First classify both operands.  */  if (REG_P (op0))    optype0 = REGOP;  else if (offsettable_memref_p (op0))    optype0 = OFFSOP;  else if (GET_CODE (op0) == MEM)    optype0 = MEMOP;  else    optype0 = RNDOP;  if (REG_P (op1))    optype1 = REGOP;  else if (CONSTANT_P (op1))    optype1 = CNSTOP;  else if (offsettable_memref_p (op1))    optype1 = OFFSOP;  else if (GET_CODE (op1) == 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      || (optype0 == MEM && optype1 == MEM))    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 (op0, 0));  if (optype1 == MEMOP)    addreg1 = find_addr_reg (XEXP (op1, 0));  /* Ok, we can do one word at a time.     Set up in LATEHALF the operands to use for the     high-numbered (least significant) 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 (op0) + 1);  else if (optype0 == OFFSOP)    latehalf[0] = adj_offsettable_operand (op0, 4);  else    latehalf[0] = op0;  if (optype1 == REGOP)    latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1);  else if (optype1 == OFFSOP)    latehalf[1] = adj_offsettable_operand (op1, 4);  else if (optype1 == CNSTOP)    split_double (op1, &operands[1], &latehalf[1]);  else    latehalf[1] = op1;  /* Easy case: try moving both words at once.  Check for moving between     an even/odd register pair and a memory location.  */  if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP       && (REGNO (op0) & 1) == 0)      || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP	  && (REGNO (op1) & 1) == 0))    {      register rtx mem;      if (optype0 == REGOP)	mem = op1;      else	mem = op0;      if (mem_aligned_8 (mem))	return (mem == op1 ? "ldd %1,%0" : "std %1,%0");    }  /* If the first move would clobber the source of the second one,     do them in the other order.  */  /* Overlapping registers.  */  if (optype0 == REGOP && optype1 == REGOP      && REGNO (op0) == REGNO (latehalf[1]))    {      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Do low-numbered word.  */      return singlemove_string (operands);    }  /* Loading into a register which overlaps a register used in the address.  */  else if (optype0 == REGOP && optype1 != REGOP	   && reg_overlap_mentioned_p (op0, op1))    {      /* ??? This fails if the address is a double register address, each	 of which is clobbered by operand 0.  */      /* 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 ("add %0,0x4,%0", &addreg0);  if (addreg1)    output_asm_insn ("add %0,0x4,%0", &addreg1);  /* Do that word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    output_asm_insn ("add %0,-0x4,%0", &addreg0);  if (addreg1)    output_asm_insn ("add %0,-0x4,%0", &addreg1);  return "";}/* Output assembler code to perform a quadword move insn   with operands OPERANDS.  This is very similar to the preceding   output_move_double function.  */char *output_move_quad (operands)     rtx *operands;{  register rtx op0 = operands[0];  register rtx op1 = operands[1];  register enum optype optype0;  register enum optype optype1;  rtx wordpart[4][2];  rtx addreg0 = 0;  rtx addreg1 = 0;  /* First classify both operands.  */  if (REG_P (op0))    optype0 = REGOP;  else if (offsettable_memref_p (op0))    optype0 = OFFSOP;  else if (GET_CODE (op0) == MEM)    optype0 = MEMOP;  else    optype0 = RNDOP;  if (REG_P (op1))    optype1 = REGOP;  else if (CONSTANT_P (op1))    optype1 = CNSTOP;  else if (offsettable_memref_p (op1))    optype1 = OFFSOP;  else if (GET_CODE (op1) == 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      || (optype0 == MEM && optype1 == MEM))    abort ();  /* If an operand is an unoffsettable memory ref, find a register     we can increment temporarily to make it refer to the later words.  */  if (optype0 == MEMOP)    addreg0 = find_addr_reg (XEXP (op0, 0));  if (optype1 == MEMOP)    addreg1 = find_addr_reg (XEXP (op1, 0));  /* Ok, we can do one word at a time.     Set up in wordpart the operands to use for each word of the arguments.  */  if (optype0 == REGOP)    {      wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0);      wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1);      wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2);      wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3);    }  else if (optype0 == OFFSOP)    {      wordpart[0][0] = adj_offsettable_operand (op0, 0);      wordpart[1][0] = adj_offsettable_operand (op0, 4);      wordpart[2][0] = adj_offsettable_operand (op0, 8);      wordpart[3][0] = adj_offsettable_operand (op0, 12);    }  else    {      wordpart[0][0] = op0;      wordpart[1][0] = op0;      wordpart[2][0] = op0;      wordpart[3][0] = op0;    }  if (optype1 == REGOP)    {      wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0);      wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1);      wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2);      wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3);    }  else if (optype1 == OFFSOP)    {      wordpart[0][1] = adj_offsettable_operand (op1, 0);      wordpart[1][1] = adj_offsettable_operand (op1, 4);      wordpart[2][1] = adj_offsettable_operand (op1, 8);      wordpart[3][1] = adj_offsettable_operand (op1, 12);    }  else if (optype1 == CNSTOP)    {      /* This case isn't implemented yet, because there is no internal	 representation for quad-word constants, and there is no split_quad	 function.  */#if 0      split_quad (op1, &wordpart[0][1], &wordpart[1][1],		  &wordpart[2][1], &wordpart[3][1]);#else      abort ();#endif    }  else    {      wordpart[0][1] = op1;      wordpart[1][1] = op1;      wordpart[2][1] = op1;      wordpart[3][1] = op1;    }  /* Easy case: try moving the quad as two pairs.  Check for moving between     an even/odd register pair and a memory location.  */  /* ??? Should also handle the case of non-offsettable addresses here.     We can at least do the first pair as a ldd/std, and then do the third     and fourth words individually.  */  if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0)      || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0))    {      rtx mem;      if (optype0 == REGOP)	mem = op1;      else	mem = op0;      if (mem_aligned_8 (mem))	{	  operands[2] = adj_offsettable_operand (mem, 8);	  if (mem == op1)	    return "ldd %1,%0;ldd %2,%S0";	  else	    return "std %1,%0;std %S1,%2";	}    }  /* If the first move would clobber the source of the second one,     do them in the other order.  */  /* Overlapping registers.  */  if (optype0 == REGOP && optype1 == REGOP      && (REGNO (op0) == REGNO (wordpart[1][3])	  || REGNO (op0) == REGNO (wordpart[1][2])	  || REGNO (op0) == REGNO (wordpart[1][1])))    {      /* Do fourth word.  */      output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);      /* Do the third word.  */      output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);      /* Do the second word.  */      output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);      /* Do lowest-numbered word.  */      return singlemove_string (wordpart[0]);    }  /* Loading into a register which overlaps a register used in the address.  */  if (optype0 == REGOP && optype1 != REGOP

⌨️ 快捷键说明

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