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

📄 pa.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
     rtx X;{  if (GET_CODE (X) == PLUS)      return 1;  else if (GET_CODE (X) == LO_SUM)    return 1;  else if (GET_CODE (X) == HIGH)    return 2;  return 4;}/* Emit insns to move operands[1] into operands[0].   Return 1 if we have written out everything that needs to be done to   do the move.  Otherwise, return 0 and the caller will emit the move   normally.  */intemit_move_sequence (operands, mode, scratch_reg)     rtx *operands;     enum machine_mode mode;     rtx scratch_reg;{  register rtx operand0 = operands[0];  register rtx operand1 = operands[1];  if (fp_reg_operand (operand0, mode)      && GET_CODE (operand1) == MEM      && !short_memory_operand  (operand1, mode)      && scratch_reg)    {      emit_move_insn (scratch_reg, XEXP (operand1 , 0));      emit_insn (gen_rtx (SET, VOIDmode, operand0, gen_rtx (MEM, mode,							    scratch_reg)));      return 1;    }  else if (fp_reg_operand (operand1, mode)	   && GET_CODE (operand0) == MEM	   && !short_memory_operand  (operand0, mode)	   && scratch_reg)    {      emit_move_insn (scratch_reg, XEXP (operand0 , 0));      emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, mode,  scratch_reg),			  operand1));      return 1;    }  /* Handle most common case: storing into a register.  */  else if (register_operand (operand0, mode))    {      if (register_operand (operand1, mode)	  || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))	  || (GET_CODE (operand1) == HIGH	      && !symbolic_operand (XEXP (operand1, 0)))	  /* Only `general_operands' can come here, so MEM is ok.  */	  || GET_CODE (operand1) == MEM)	{	  /* Run this case quickly.  */	  emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));	  return 1;	}    }  else if (GET_CODE (operand0) == MEM)    {      if (register_operand (operand1, mode) || operand1 == const0_rtx)	{	  /* Run this case quickly.  */	  emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));	  return 1;	}      if (! reload_in_progress)	{	  operands[0] = validize_mem (operand0);	  operands[1] = operand1 = force_reg (mode, operand1);	}    }  /* Simplify the source if we need to.  */  if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))    {      if (symbolic_operand (operand1, mode))	{	  if (flag_pic)	    {	      rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (Pmode);	      operands[1] = legitimize_pic_address (operand1, mode, temp);	    }	  /* On the HPPA, references to data space are supposed to */	  /* use dp, register 27. */	  else if (read_only_operand (operand1))	    {	      rtx set = gen_rtx (SET, VOIDmode,				  operand0,				  gen_rtx (LO_SUM, mode, operand0, operand1));				 	      emit_insn (gen_rtx (SET, VOIDmode,				  operand0,				  gen_rtx (HIGH, mode, operand1)));	      if (TARGET_SHARED_LIBS		  && function_label_operand (operand1, mode))		{		  rtx temp = reload_in_progress ? scratch_reg		    : gen_reg_rtx (mode);		  if (!temp)		    abort ();		  emit_insn (gen_rtx (PARALLEL, VOIDmode,				      gen_rtvec (2,						 set,						 gen_rtx (CLOBBER, VOIDmode,							  temp))));		}	      else		emit_insn (set);	      return 1;	    }	  else	    {	      /* If reload_in_progress, we can't use addil and r1; we */	      /* have to use the more expensive ldil sequence. */	      if (reload_in_progress)		{		  emit_insn (gen_rtx (SET, VOIDmode,				      operand0,				      gen_rtx (HIGH, mode, operand1)));		  emit_insn (gen_rtx (SET, VOIDmode,				      operand0,				      gen_rtx (PLUS, mode,					       operand0,					       gen_rtx (REG, mode, 27))));		  emit_insn (gen_rtx (SET, VOIDmode,				      operand0,				      gen_rtx (LO_SUM, mode,					       operand0, operand1)));		}	      else		{		  rtx temp1, temp2 = gen_reg_rtx (mode);		  /* For 2.4 we could set RTX_UNCHANGING and add a 		     REG_EQUAL note for the first insn.  This would 		     allow the first insn to be moved out of loops.  */		  temp1 = gen_rtx (HIGH, mode, operand1);		  emit_insn (gen_rtx (SET, VOIDmode,				      temp2,				      gen_rtx (PLUS, mode,					       gen_rtx (REG, mode, 27),					       temp1)));		  emit_insn (gen_rtx (SET, VOIDmode,				      operand0,				      gen_rtx (LO_SUM, mode,					       temp2, operand1)));		}	      return 1;	    }	}      else if (depi_cint_operand (operand1, VOIDmode))	return 0;      else if (GET_CODE (operand1) == CONST_INT	       ? (! SMALL_INT (operand1)		  && (INTVAL (operand1) & 0x7ff) != 0) : 1)	{	  rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (mode);	  emit_insn (gen_rtx (SET, VOIDmode, temp,			      gen_rtx (HIGH, mode, operand1)));	  operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);	}    }  /* Now have insn-emit do whatever it normally does.  */  return 0;}/* Does operand (which is a symbolic_operand) live in text space? If   so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true.*/intread_only_operand (operand)     rtx operand;{  if (GET_CODE (operand) == CONST)    operand = XEXP (XEXP (operand, 0), 0);  if (GET_CODE (operand) == SYMBOL_REF)    return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);  return 1;}     /* 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)    return "stw %r1,%0";  if (GET_CODE (operands[1]) == MEM)    return "ldw %1,%0";  if (GET_CODE (operands[1]) == CONST_INT)    if (INT_14_BITS (operands[1]))      return (INTVAL (operands[1]) == 0 ? "copy 0,%0" : "ldi %1,%0");    else      return "ldil L'%1,%0\n\tldo R'%1(%0),%0";  return "copy %1,%0";}/* Compute position (in OPERANDS[2]) and width (in OPERANDS[3])   useful for copying or or'ing IMM to a register using bit field   instructions.  Store the immediate value to insert in OPERANDS[1].  */voidcompute_xdepi_operands_from_integer (imm, operands)     unsigned imm;     rtx *operands;{  int lsb, len;  /* Find the least significant set bit in IMM.  */  for (lsb = 0; lsb < 32; lsb++)    {      if ((imm & 1) != 0)        break;      imm >>= 1;    }  /* Choose variants based on *sign* of the 5-bit field.  */  if ((imm & 0x10) == 0)    len = (lsb <= 28) ? 4 : 32 - lsb;  else    {      /* Find the width of the bitstring in IMM.  */      for (len = 5; len < 32; len++)	{	  if ((imm & (1 << len)) == 0)	    break;	}      /* Sign extend IMM as a 5-bit value.  */      imm = (imm & 0xf) - 0x10;    }  operands[1] = gen_rtx (CONST_INT, VOIDmode, imm);  operands[2] = gen_rtx (CONST_INT, VOIDmode, 31 - lsb);  operands[3] = gen_rtx (CONST_INT, VOIDmode, len);}/* Output assembler code to perform a doubleword move insn   with operands OPERANDS.  */char *output_move_double (operands)     rtx *operands;{  enum { REGOP, OFFSOP, MEMOP, 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]))    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 != REGOP && optype1 != REGOP)    abort ();   /* Handle auto decrementing and incrementing loads and stores     specifically, since the structure of the function doesn't work     for them without major modification.  Do it better when we learn     this port about the general inc/dec addressing of PA.     (This was written by tege.  Chide him if it doesn't work.)  */  if (optype0 == MEMOP)    {      /* We have to output the address syntax ourselves, since print_operand	 doesn't deal with the addresses we want to use.  Fix this later.  */      rtx addr = XEXP (operands[0], 0);      if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)	{	  rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);	  operands[0] = XEXP (addr, 0);	  if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)	    abort ();	  if (!reg_overlap_mentioned_p (high_reg, addr))	    {	      /* No overlap between high target register and address		 register.  (We do this in a non-obvious way to		 save a register file writeback)  */	      if (GET_CODE (addr) == POST_INC)		return "stws,ma %1,8(0,%0)\n\tstw %R1,-4(0,%0)";	      return "stws,ma %1,-8(0,%0)\n\tstw %R1,12(0,%0)";	    }	  else	    abort();	}      else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)	{	  rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0);	  operands[0] = XEXP (addr, 0);	  if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)	    abort ();	  if (!reg_overlap_mentioned_p (high_reg, addr))	    {	      /* No overlap between high target register and address		 register.  (We do this in a non-obvious way to		 save a register file writeback)  */	      if (GET_CODE (addr) == PRE_INC)		return "stws,mb %1,8(0,%0)\n\tstw %R1,4(0,%0)";	      return "stws,mb %1,-8(0,%0)\n\tstw %R1,4(0,%0)";	    }	  else	    abort();	}    }  if (optype1 == MEMOP)    {      /* We have to output the address syntax ourselves, since print_operand	 doesn't deal with the addresses we want to use.  Fix this later.  */      rtx addr = XEXP (operands[1], 0);      if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)	{	  rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);	  operands[1] = XEXP (addr, 0);	  if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)	    abort ();	  if (!reg_overlap_mentioned_p (high_reg, addr))	    {	      /* No overlap between high target register and address		 register.  (We do this in a non-obvious way to		 save a register file writeback)  */	      if (GET_CODE (addr) == POST_INC)		return "ldws,ma 8(0,%1),%0\n\tldw -4(0,%1),%R0";	      return "ldws,ma -8(0,%1),%0\n\tldw 12(0,%1),%R0";	    }	  else	    {	      /* This is an undefined situation.  We should load into the		 address register *and* update that register.  Probably		 we don't need to handle this at all.  */	      if (GET_CODE (addr) == POST_INC)		return "ldw 4(0,%1),%R0\n\tldws,ma 8(0,%1),%0";	      return "ldw 4(0,%1),%R0\n\tldws,ma -8(0,%1),%0";	    }	}      else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)	{	  rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0);	  operands[1] = XEXP (addr, 0);	  if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)	    abort ();	  if (!reg_overlap_mentioned_p (high_reg, addr))	    {	      /* No overlap between high target register and address		 register.  (We do this in a non-obvious way to		 save a register file writeback)  */	      if (GET_CODE (addr) == PRE_INC)		return "ldws,mb 8(0,%1),%0\n\tldw 4(0,%1),%R0";	      return "ldws,mb -8(0,%1),%0\n\tldw 4(0,%1),%R0";	    }	  else	    {	      /* This is an undefined situation.  We should load into the		 address register *and* update that register.  Probably		 we don't need to handle this at all.  */	      if (GET_CODE (addr) == PRE_INC)		return "ldw 12(0,%1),%R0\n\tldws,mb 8(0,%1),%0";	      return "ldw -4(0,%1),%R0\n\tldws,mb -8(0,%1),%0";	    }	}    }  /* 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));  /* Ok, we can do one word at a time.     Normally we do the low-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)    split_double (operands[1], &operands[1], &latehalf[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 HP-PA when loading parameter registers,     so I am going to define that circumstance, and make it work     as expected.  */  if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP)	   && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))    {      /* XXX THIS PROBABLY DOESN'T WORK.  */      /* Do the late half first.  */      if (addreg1)	output_asm_insn ("ldo 4(%0),%0", &addreg1);      output_asm_insn (singlemove_string (latehalf), latehalf);      if (addreg1)	output_asm_insn ("ldo -4(%0),%0", &addreg1);      /* Then clobber.  */      return singlemove_string (operands);    }  if (optype0 == REGOP && optype1 == REGOP      && REGNO (operands[0]) == REGNO (operands[1]) + 1)    {      output_asm_insn (singlemove_string (latehalf), latehalf);      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 ("ldo 4(%0),%0", &addreg0);  if (addreg1)    output_asm_insn ("ldo 4(%0),%0", &addreg1);  /* Do that word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    output_asm_insn ("ldo -4(%0),%0", &addreg0);  if (addreg1)    output_asm_insn ("ldo -4(%0),%0", &addreg1);  return "";}char *output_fp_move_double (operands)     rtx *operands;{  if (FP_REG_P (operands[0]))    {      if (FP_REG_P (operands[1]))	output_asm_insn ("fcpy,dbl %1,%0", operands);      else if (GET_CODE (operands[1]) == REG)	{	  rtx xoperands[3];	  xoperands[0] = operands[0];	  xoperands[1] = operands[1];	  xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);	  output_asm_insn	    ("stw %1,-16(0,30)\n\tstw %2,-12(0,30)\n\tfldds -16(0,30),%0",			   xoperands);	}      else 	output_asm_insn ("fldds%F1 %1,%0", operands);    }  else if (FP_REG_P (operands[1]))    {

⌨️ 快捷键说明

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