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

📄 m68k.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
    {      if (reg == 0)	abort ();      pic_ref = gen_rtx (MEM, Pmode,			 gen_rtx (PLUS, Pmode,				  pic_offset_table_rtx, orig));      current_function_uses_pic_offset_table = 1;      RTX_UNCHANGING_P (pic_ref) = 1;      emit_move_insn (reg, pic_ref);      return reg;    }  else if (GET_CODE (orig) == CONST)    {      rtx base, offset;      /* Make sure this is CONST has not already been legitimized */      if (GET_CODE (XEXP (orig, 0)) == PLUS	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)	return orig;      if (reg == 0)	abort ();      /* legitimize both operands of the PLUS */      if (GET_CODE (XEXP (orig, 0)) == PLUS)	{	  base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);	  orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,					 base == reg ? 0 : reg);	}      else abort ();      if (GET_CODE (orig) == CONST_INT)	return plus_constant_for_output (base, INTVAL (orig));      pic_ref = gen_rtx (PLUS, Pmode, base, orig);      /* Likewise, should we set special REG_NOTEs here?  */    }  return pic_ref;}typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;use_movq (i)     int i;{  return (i >= -128 && i <= 127);}CONST_METHODconst_method (constant)     rtx constant;{  int i;  unsigned u;  i = INTVAL (constant);  if (use_movq (i))    return MOVQ;  /* if -256 < N < 256 but N is not in range for a moveq     N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */  if (use_movq (i ^ 0xff))    return NOTB;  /* Likewise, try with not.w */  if (use_movq (i ^ 0xffff))    return NOTW;  /* This is the only value where neg.w is useful */  if (i == -65408)    return NEGW;  /* Try also with swap */  u = i;  if (use_movq ((u >> 16) | (u << 16)))    return SWAP;  /* Otherwise, use move.l */  return MOVL;}const_int_cost (constant)     rtx constant;{  switch (const_method (constant))    {      case MOVQ :      /* Constants between -128 and 127 are cheap due to moveq */	return 0;      case NOTB :      case NOTW :      case NEGW :      case SWAP :      /* Constants easily generated by moveq + not.b/not.w/neg.w/swap  */        return 1;      case MOVL :	return 2;      default :        abort ();    }}char *output_move_const_into_data_reg (operands)     rtx *operands;{  int i;  i = INTVAL (operands[1]);  switch (const_method (operands[1]))    {    case MOVQ :#if defined (MOTOROLA) && !defined (CRDS)      return "moveq%.l %1,%0";#else      return "moveq %1,%0";#endif    case NOTB :      operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xff);#if defined (MOTOROLA) && !defined (CRDS)      return "moveq%.l %1,%0\n\tnot%.b %0";#else      return "moveq %1,%0\n\tnot%.b %0";#endif	     case NOTW :      operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xffff);#if defined (MOTOROLA) && !defined (CRDS)      return "moveq%.l %1,%0\n\tnot%.w %0";#else      return "moveq %1,%0\n\tnot%.w %0";#endif	     case NEGW :#if defined (MOTOROLA) && !defined (CRDS)      return "moveq%.l %#-128,%0\n\tneg%.w %0";#else      return "moveq %#-128,%0\n\tneg%.w %0";#endif	     case SWAP :      {	unsigned u = i;	operands[1] = gen_rtx (CONST_INT, VOIDmode, (u << 16) | (u >> 16));#if defined (MOTOROLA) && !defined (CRDS)	return "moveq%.l %1,%0\n\tswap %0";#else	return "moveq %1,%0\n\tswap %0";#endif	       }    case MOVL :	return "move%.l %1,%0";    default :	abort ();    }}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */static char *singlemove_string (operands)     rtx *operands;{#ifdef SUPPORT_SUN_FPA  if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))    return "fpmoves %1,%0";#endif  if (DATA_REG_P (operands[0])      && GET_CODE (operands[1]) == CONST_INT)      return output_move_const_into_data_reg (operands);  if (operands[1] != const0_rtx)    return "move%.l %1,%0";  if (! ADDRESS_REG_P (operands[0]))    return "clr%.l %0";  return "sub%.l %0,%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 middlehalf[2];  rtx xops[2];  rtx addreg0 = 0, addreg1 = 0;  int dest_overlapped_low = 0;  int size = GET_MODE_SIZE (GET_MODE (operands[0]));  middlehalf[0] = 0;  middlehalf[1] = 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 (XEXP (operands[0], 0)) == POST_INC)    optype0 = POPOP;  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)    optype0 = PUSHOP;  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 (XEXP (operands[1], 0)) == POST_INC)    optype1 = POPOP;  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)    optype1 = PUSHOP;  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 one operand is decrementing and one is incrementing     decrement the former register explicitly     and change that operand into ordinary indexing.  */  if (optype0 == PUSHOP && optype1 == POPOP)    {      operands[0] = XEXP (XEXP (operands[0], 0), 0);      if (size == 12)        output_asm_insn ("sub%.l %#12,%0", operands);      else        output_asm_insn ("subq%.l %#8,%0", operands);      if (GET_MODE (operands[1]) == XFmode)	operands[0] = gen_rtx (MEM, XFmode, operands[0]);      else if (GET_MODE (operands[0]) == DFmode)	operands[0] = gen_rtx (MEM, DFmode, operands[0]);      else	operands[0] = gen_rtx (MEM, DImode, operands[0]);      optype0 = OFFSOP;    }  if (optype0 == POPOP && optype1 == PUSHOP)    {      operands[1] = XEXP (XEXP (operands[1], 0), 0);      if (size == 12)        output_asm_insn ("sub%.l %#12,%1", operands);      else        output_asm_insn ("subq%.l %#8,%1", operands);      if (GET_MODE (operands[1]) == XFmode)	operands[1] = gen_rtx (MEM, XFmode, operands[1]);      else if (GET_MODE (operands[1]) == DFmode)	operands[1] = gen_rtx (MEM, DFmode, operands[1]);      else	operands[1] = gen_rtx (MEM, DImode, operands[1]);      optype1 = OFFSOP;    }  /* 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 (size == 12)    {      if (optype0 == REGOP)	{	  latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);	  middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);	}      else if (optype0 == OFFSOP)	{	  middlehalf[0] = adj_offsettable_operand (operands[0], 4);	  latehalf[0] = adj_offsettable_operand (operands[0], size - 4);	}      else	{	  middlehalf[0] = operands[0];	  latehalf[0] = operands[0];	}      if (optype1 == REGOP)	{	  latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);	  middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);	}      else if (optype1 == OFFSOP)	{	  middlehalf[1] = adj_offsettable_operand (operands[1], 4);	  latehalf[1] = adj_offsettable_operand (operands[1], size - 4);	}      else if (optype1 == CNSTOP)	{	  if (GET_CODE (operands[1]) == CONST_DOUBLE)	    {	      REAL_VALUE_TYPE r;	      long l[3];	      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);	      REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);	      operands[1] = GEN_INT (l[0]);	      middlehalf[1] = GEN_INT (l[1]);	      latehalf[1] = GEN_INT (l[2]);	    }	  else if (CONSTANT_P (operands[1]))	    {	      /* actually, no non-CONST_DOUBLE constant should ever		 appear here.  */	      abort ();	      if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)		latehalf[1] = constm1_rtx;	      else		latehalf[1] = const0_rtx;	    }	}      else	{	  middlehalf[1] = operands[1];	  latehalf[1] = operands[1];	}    }  else    /* size is not 12: */    {      if (optype0 == REGOP)	latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);      else if (optype0 == OFFSOP)	latehalf[0] = adj_offsettable_operand (operands[0], size - 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], size - 4);      else if (optype1 == CNSTOP)	split_double (operands[1], &operands[1], &latehalf[1]);      else	latehalf[1] = operands[1];    }  /* If insn is effectively movd N(sp),-(sp) then we will do the     high word first.  We should use the adjusted operand 1 (which is N+4(sp))     for the low word as well, to compensate for the first decrement of sp.  */  if (optype0 == PUSHOP      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))    operands[1] = middlehalf[1] = latehalf[1];  /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),     if the upper part of reg N does not appear in the MEM, arrange to     emit the move late-half first.  Otherwise, compute the MEM address     into the upper part of N and use that as a pointer to the memory     operand.  */  if (optype0 == REGOP      && (optype1 == OFFSOP || optype1 == MEMOP))    {      rtx testlow = gen_rtx (REG, SImode, REGNO (operands[0]));      if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))	  && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	{	  /* If both halves of dest are used in the src memory address,	     compute the address into latehalf of dest.	     Note that this can't happen if the dest is two data regs.  */compadr:	  xops[0] = latehalf[0];	  xops[1] = XEXP (operands[1], 0);	  output_asm_insn ("lea %a1,%0", xops);	  if( GET_MODE (operands[1]) == XFmode )	    {	      operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);	      middlehalf[1] = adj_offsettable_operand (operands[1], size-8);	      latehalf[1] = adj_offsettable_operand (operands[1], size-4);	    }	  else	    {	      operands[1] = gen_rtx (MEM, DImode, latehalf[0]);	      latehalf[1] = adj_offsettable_operand (operands[1], size-4);	    }	}      else if (size == 12	       && reg_overlap_mentioned_p (middlehalf[0],					   XEXP (operands[1], 0)))	{	  /* Check for two regs used by both source and dest.	     Note that this can't happen if the dest is all data regs.	     It can happen if the dest is d6, d7, a0.	     But in that case, latehalf is an addr reg, so	     the code at compadr does ok.  */	  if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))	      || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	    goto compadr;	  /* JRV says this can't happen: */	  if (addreg0 || addreg1)	    abort ();	  /* Only the middle reg conflicts; simply put it last. */	  output_asm_insn (singlemove_string (operands), operands);	  output_asm_insn (singlemove_string (latehalf), latehalf);	  output_asm_insn (singlemove_string (middlehalf), middlehalf);	  return "";	}      else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))	/* If the low half of dest is mentioned in the source memory	   address, the arrange to emit the move late half first.  */	dest_overlapped_low = 1;    }  /* If one or both operands autodecrementing,     do the two words, high-numbered first.  */  /* Likewise,  the first move would clobber the source of the second one,     do them in the other order.  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.  */  if (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))	      || REGNO (operands[0]) == REGNO (latehalf[1])))      || dest_overlapped_low)    {      /* Make any unoffsettable addresses point at high-numbered word.  */      if (addreg0)	{	  if (size == 12)	    output_asm_insn ("addq%.l %#8,%0", &addreg0);	  else	    output_asm_insn ("addq%.l %#4,%0", &addreg0);	}      if (addreg1)	{	  if (size == 12)	    output_asm_insn ("addq%.l %#8,%0", &addreg1);	  else	    output_asm_insn ("addq%.l %#4,%0", &addreg1);	}      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Undo the adds we just did.  */      if (addreg0)	output_asm_insn ("subq%.l %#4,%0", &addreg0);      if (addreg1)	output_asm_insn ("subq%.l %#4,%0", &addreg1);      if (size == 12)	{	  output_asm_insn (singlemove_string (middlehalf), middlehalf);	  if (addreg0)	    output_asm_insn ("subq%.l %#4,%0", &addreg0);	  if (addreg1)	    output_asm_insn ("subq%.l %#4,%0", &addreg1);	}      /* Do low-numbered word.  */      return singlemove_string (operands);    }  /* Normal case: do the two words, low-numbered first.  */  output_asm_insn (singlemove_string (operands), operands);  /* Do the middle one of the three words for long double */  if (size == 12)    {      if (addreg0)	output_asm_insn ("addq%.l %#4,%0", &addreg0);      if (addreg1)	output_asm_insn ("addq%.l %#4,%0", &addreg1);      output_asm_insn (singlemove_string (middlehalf), middlehalf);    }

⌨️ 快捷键说明

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