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

📄 out-sparc.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    }  return 0;}/* Return truth value of wheterh OP is EQ or NE.  */inteq_or_neq (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* Return truth value of whether OP can be used as an operands in a three   address arithmetic insn (such as add %o1,7,%l2) of mode MODE.  */intarith_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return truth value of whether OP can be used as an operand in a two   address arithmetic insn (such as set 123456,%o4) of mode MODE.  */intarith32_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);}/* Return truth value of whether OP is a integer which fits the   range constraining immediate operands in three-address insns.  */intsmall_int (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && SMALL_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_G1)		   && cc_prev_status.mdep == XEXP (operands[0], 0)))	      output_asm_insn ("sethi %%hi(%m0),%%g1", operands);	    cc_status.flags |= CC_KNOW_HI_G1;	    cc_status.mdep = XEXP (operands[0], 0);	    return "st %1,[%%lo(%m0)+%%g1]";	  }	else	  return "st %r1,%0";      else	{	  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 "";	}    }  if (GET_CODE (operands[1]) == MEM)    {      if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)		 && cc_prev_status.mdep == XEXP (operands[1], 0)))	    output_asm_insn ("sethi %%hi(%m1),%%g1", operands);	  cc_status.flags |= CC_KNOW_HI_G1;	  cc_status.mdep = XEXP (operands[1], 0);	  return "ld [%%lo(%m1)+%%g1],%0";	}      return "ld %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));  /* 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.  */  /* Easy case: try moving both words at once.  */  /* First check for moving between an even/odd register pair     and a memory location.  */  if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP       && (REGNO (operands[0]) & 1) == 0)      || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP	  && (REGNO (operands[1]) & 1) == 0))    {      rtx op1, op2;      rtx base = 0, offset = const0_rtx;      /* OP1 gets the register pair, and OP2 gets the memory address.  */      if (optype0 == REGOP)	op1 = operands[0], op2 = XEXP (operands[1], 0);      else	op1 = operands[1], op2 = XEXP (operands[0], 0);      /* Now see if we can trust the address to be 8-byte aligned.  */      /* Trust global variables.  */      if (CONSTANT_ADDRESS_P (op2))	{	  operands[0] = op1;	  operands[1] = op2;	  if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)		 && cc_prev_status.mdep == op2))	    output_asm_insn ("sethi %%hi(%1),%%g1", operands);	  cc_status.flags |= CC_KNOW_HI_G1;	  cc_status.mdep = op2;	  if (op1 == operands[0])	    return "ldd [%%lo(%1)+%%g1],%0";	  else	    return "std [%%lo(%1)+%%g1],%0";	}      if (GET_CODE (op2) == PLUS)	{	  if (GET_CODE (XEXP (op2, 0)) == REG)	    base = XEXP (op2, 0), offset = XEXP (op2, 1);	  else if (GET_CODE (XEXP (op2, 1)) == REG)	    base = XEXP (op2, 1), offset = XEXP (op2, 0);	}      /* Trust round enough offsets from the stack or frame pointer.  */      if (base	  && (REGNO (base) == FRAME_POINTER_REGNUM	      || REGNO (base) == STACK_POINTER_REGNUM))	{	  if (GET_CODE (offset) == CONST_INT	      && (INTVAL (offset) & 0x7) == 0)	    {	      if (op1 == operands[0])		return "ldd %1,%0";	      else		return "std %1,%0";	    }	}      else	{	  /* We know structs not on the stack are properly aligned.	     Since a double asks for 8-byte alignment,	     we know it must have got that if it is in a struct.	     But a DImode need not be 8-byte aligned, because it could be a	     struct containing two ints or pointers.  */	  /* Sun fucks us here.  We cannot trust references	     to doubles via varying addresses.  It might be on the stack	     even if we don't know that it is; and then it might not be	     double-word aligned.  */#if 0	  if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode	      && MEM_IN_STRUCT_P (operands[1]))	    return "ldd %1,%0";	  else if (GET_CODE (operands[0]) == MEM		   && GET_MODE (operands[0]) == DFmode		   && MEM_IN_STRUCT_P (operands[0]))	    return "std %1,%0";#endif	}    }  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 ("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);      /* 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 ("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 "";}static char *output_fp_move_double (operands)     rtx *operands;{  if (FP_REG_P (operands[0]))    {      if (FP_REG_P (operands[1]))	{	  output_asm_insn ("fmovs %1,%0", operands);	  operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);	  operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);	  return "fmovs %1,%0";	}      if (GET_CODE (operands[1]) == REG)	{	  if ((REGNO (operands[1]) & 1) == 0)	    return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";	  else	    {	      rtx xoperands[3];	      xoperands[0] = operands[0];	      xoperands[1] = operands[1];	      xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);	      output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);	      return "";	    }	}      /* Use ldd if known to be aligned.  */      if (GET_CODE (XEXP (operands[1], 0)) == PLUS	  && (((XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx		|| XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)	       && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT	       && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) == 0)#if 0 /* An array in a structure that is a parm need not be aligned!  */	      /* Arrays are known to be aligned,		 and reg+reg addresses are used (on this machine)		 only for array accesses.  */	      || (REG_P (XEXP (XEXP (operands[1], 0), 0))		  && REG_P (XEXP (XEXP (operands[1], 0), 1)))#endif	      ))	return "ldd %1,%0";      if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)		 && cc_prev_status.mdep == XEXP (operands[1], 0)))	    output_asm_insn ("sethi %%hi(%m1),%%g1", operands);	  cc_status.flags |= CC_KNOW_HI_G1;	  cc_status.mdep = XEXP (operands[1], 0);	  return "ldd [%%lo(%m1)+%%g1],%0";	}      /* Otherwise use two ld insns.  */      {	rtx xoperands[2];	output_asm_insn ("ld %1,%0", operands);	xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]),				REGNO (operands[0]) + 1);	if (GET_CODE (XEXP (operands[1], 0)) == PLUS	    && offsettable_address_p (1, GET_MODE (operands[1]),				      XEXP (operands[1], 0)))	  {	    xoperands[1] = adj_offsettable_operand (operands[1], 4);	    output_asm_insn ("ld %1,%0", xoperands);	  }	else if (GET_CODE (XEXP (operands[1], 0)) == PLUS)	  {	    rtx memref = operands[1];	    rtx inc_reg = XEXP (XEXP (operands[1], 0), 0);	    if (inc_reg == frame_pointer_rtx		&& GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG		&& XEXP (XEXP (operands[1], 0), 1) != frame_pointer_rtx)	      inc_reg = XEXP (XEXP (operands[1], 0), 1);	    if (inc_reg == frame_pointer_rtx)	      {		output_asm_insn ("mov %%fp,%%g1", xoperands);		inc_reg = gen_rtx (REG, SImode, 1);		memref = gen_rtx (GET_CODE (operands[1]),				  GET_MODE (operands[1]),				  gen_rtx (PLUS, GET_MODE (XEXP (operands[1], 0)),					   inc_reg,					   XEXP (XEXP (operands[1], 0), 1)));	      }	    xoperands[1] = inc_reg;	    output_asm_insn ("add 4,%1,%1", xoperands);	    xoperands[1] = memref;	    output_asm_insn ("ld %1,%0", xoperands);	    xoperands[1] = inc_reg;	    output_asm_insn ("add -4,%1,%1", xoperands);	  }	else	  {	    xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),				plus_constant (XEXP (operands[1], 0), 4));	    output_asm_insn ("ld %1,%0", xoperands);	  }	return "";      }    }  else if (FP_REG_P (operands[1]))    {      if (GET_CODE (operands[0]) == REG)	{	  if ((REGNO (operands[0]) & 1) == 0)	    return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";	  else	    {	      rtx xoperands[3];	      xoperands[2] = operands[1];	      xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);	      xoperands[0] = operands[0];	      output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);	      return "";	    }	}      /* Use std if we can be sure it is well-aligned.  */      if (GET_CODE (XEXP (operands[0], 0)) == PLUS	  && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx		|| XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)	       && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT	       && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0)#if 0 /* An array in a structure that is a parm need not be aligned!  */	      /* Arrays are known to be aligned,		 and reg+reg addresses are used (on this machine)		 only for array accesses.  */	      || (REG_P (XEXP (XEXP (operands[0], 0), 0))		  && REG_P (XEXP (XEXP (operands[0], 0), 1)))#endif	      ))	return "std %1,%0";      if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)		 && cc_prev_status.mdep == XEXP (operands[0], 0)))	    output_asm_insn ("sethi %%hi(%m0),%%g1", operands);	  cc_status.flags |= CC_KNOW_HI_G1;	  cc_status.mdep = XEXP (operands[0], 0);	  return "std %1,[%%lo(%m0)+%%g1]";	}      /* Otherwise use two st insns.  */      {	rtx xoperands[2];	output_asm_insn ("st %r1,%0", operands);	xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),				REGNO (operands[1]) + 1);	if (GET_CODE (XEXP (operands[0], 0)) == PLUS	    && offsettable_address_p (1, GET_MODE (operands[0]),				      XEXP (operands[0], 0)))	  {	    xoperands[0] = adj_offsettable_operand (operands[0], 4);	    output_asm_insn ("st %r1,%0", xoperands);	  }	else if (GET_CODE (XEXP (operands[0], 0)) == PLUS)	  {	    rtx memref = operands[0];	    rtx inc_reg = XEXP (XEXP (operands[0], 0), 0);	    if (inc_reg == frame_pointer_rtx		&& GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG		&& XEXP (XEXP (operands[0], 0), 1) != frame_pointer_rtx)	      inc_reg = XEXP (XEXP (operands[0], 0), 1);	    if (inc_reg == frame_pointer_rtx)	      {		output_asm_insn ("mov %%fp,%%g1", xoperands);		inc_reg = gen_rtx (REG, SImode, 1);		memref = gen_rtx (GET_CODE (operands[0]),				  GET_MODE (operands[0]),				  gen_rtx (PLUS, GET_MODE (XEXP (operands[0], 0)),					   inc_reg,					   XEXP (XEXP (operands[0], 0), 1)));	      }	    xoperands[0] = inc_reg;	    output_asm_insn ("add 4,%0,%0", xoperands);	    xoperands[0] = memref;	    output_asm_insn ("st %r1,%0", xoperands);	    xoperands[0] = inc_reg;	    output_asm_insn ("add -4,%0,%0", xoperands);	  }	else	  {	    xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),				plus_constant (XEXP (operands[0], 0), 4));	    output_asm_insn ("st %r1,%0", xoperands);	  }	return "";      }    }  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	  && !(GET_CODE (XEXP (addr, 1)) == REG	       && XEXP (addr, 0) == frame_pointer_rtx))

⌨️ 快捷键说明

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