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

📄 m68k.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
	  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);    }  /* Make any unoffsettable addresses point at high-numbered word.  */  if (addreg0)    output_asm_insn ("addq%.l %#4,%0", &addreg0);  if (addreg1)    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)    {      if (size == 12)        output_asm_insn ("subq%.l %#8,%0", &addreg0);      else        output_asm_insn ("subq%.l %#4,%0", &addreg0);    }  if (addreg1)    {      if (size == 12)        output_asm_insn ("subq%.l %#8,%0", &addreg1);      else        output_asm_insn ("subq%.l %#4,%0", &addreg1);    }  return "";}/* 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 ();}/* Output assembler code to perform a 32 bit 3 operand add.  */char *output_addsi3 (operands)     rtx *operands;{  if (! operands_match_p (operands[0], operands[1]))    {      if (!ADDRESS_REG_P (operands[1]))	{	  rtx tmp = operands[1];	  operands[1] = operands[2];	  operands[2] = tmp;	}      /* These insns can result from reloads to access	 stack slots over 64k from the frame pointer.  */      if (GET_CODE (operands[2]) == CONST_INT	  && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000)        return "move%.l %2,%0\n\tadd%.l %1,%0";#ifdef SGS      if (GET_CODE (operands[2]) == REG)	return "lea 0(%1,%2.l),%0";      else	return "lea %c2(%1),%0";#else /* not SGS */#ifdef MOTOROLA      if (GET_CODE (operands[2]) == REG)	return "lea (%1,%2.l),%0";      else	return "lea (%c2,%1),%0";#else /* not MOTOROLA (MIT syntax) */      if (GET_CODE (operands[2]) == REG)	return "lea %1@(0,%2:l),%0";      else	return "lea %1@(%c2),%0";#endif /* not MOTOROLA */#endif /* not SGS */    }  if (GET_CODE (operands[2]) == CONST_INT)    {#ifndef NO_ADDSUB_Q      if (INTVAL (operands[2]) > 0	  && INTVAL (operands[2]) <= 8)	return "addq%.l %2,%0";      if (INTVAL (operands[2]) < 0	  && INTVAL (operands[2]) >= -8)        {	  operands[2] = GEN_INT (-INTVAL (operands[2]));	  return "subq%.l %2,%0";	}      /* On the CPU32 it is faster to use two addql instructions to	 add a small integer (8 < N <= 16) to a register.	 Likewise for subql. */      if (TARGET_CPU32 && REG_P (operands[0]))	{	  if (INTVAL (operands[2]) > 8	      && INTVAL (operands[2]) <= 16)	    {	      operands[2] = GEN_INT (INTVAL (operands[2]) - 8);	      return "addq%.l %#8,%0\n\taddq%.l %2,%0";	    }	  if (INTVAL (operands[2]) < -8	      && INTVAL (operands[2]) >= -16)	    {	      operands[2] = GEN_INT (-INTVAL (operands[2]) - 8);	      return "subq%.l %#8,%0\n\tsubq%.l %2,%0";	    }	}#endif      if (ADDRESS_REG_P (operands[0])	  && INTVAL (operands[2]) >= -0x8000	  && INTVAL (operands[2]) < 0x8000)	{	  if (TARGET_68040)	    return "add%.w %2,%0";	  else#ifdef MOTOROLA  	    return "lea (%c2,%0),%0";#else	    return "lea %0@(%c2),%0";#endif	}    }  return "add%.l %2,%0";}/* Store in cc_status the expressions that the condition codes will   describe after execution of an instruction whose pattern is EXP.   Do not alter them if the instruction would not alter the cc's.  *//* On the 68000, all the insns to store in an address register fail to   set the cc's.  However, in some cases these instructions can make it   possibly invalid to use the saved cc's.  In those cases we clear out   some or all of the saved cc's so they won't be used.  */voidnotice_update_cc (exp, insn)     rtx exp;     rtx insn;{  /* If the cc is being set from the fpa and the expression is not an     explicit floating point test instruction (which has code to deal with     this), reinit the CC.  */  if (((cc_status.value1 && FPA_REG_P (cc_status.value1))       || (cc_status.value2 && FPA_REG_P (cc_status.value2)))      && !(GET_CODE (exp) == PARALLEL	   && GET_CODE (XVECEXP (exp, 0, 0)) == SET	   && XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx))    {      CC_STATUS_INIT;     }  else if (GET_CODE (exp) == SET)    {      if (GET_CODE (SET_SRC (exp)) == CALL)	{	  CC_STATUS_INIT; 	}      else if (ADDRESS_REG_P (SET_DEST (exp)))	{	  if (cc_status.value1 && modified_in_p (cc_status.value1, insn))	    cc_status.value1 = 0;	  if (cc_status.value2 && modified_in_p (cc_status.value2, insn))	    cc_status.value2 = 0; 	}      else if (!FP_REG_P (SET_DEST (exp))	       && SET_DEST (exp) != cc0_rtx	       && (FP_REG_P (SET_SRC (exp))		   || GET_CODE (SET_SRC (exp)) == FIX		   || GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE		   || GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND))	{	  CC_STATUS_INIT; 	}      /* A pair of move insns doesn't produce a useful overall cc.  */      else if (!FP_REG_P (SET_DEST (exp))	       && !FP_REG_P (SET_SRC (exp))	       && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4	       && (GET_CODE (SET_SRC (exp)) == REG		   || GET_CODE (SET_SRC (exp)) == MEM		   || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE))	{	  CC_STATUS_INIT; 	}      else if (GET_CODE (SET_SRC (exp)) == CALL)	{	  CC_STATUS_INIT; 	}      else if (XEXP (exp, 0) != pc_rtx)	{	  cc_status.flags = 0;	  cc_status.value1 = XEXP (exp, 0);	  cc_status.value2 = XEXP (exp, 1);	}    }  else if (GET_CODE (exp) == PARALLEL	   && GET_CODE (XVECEXP (exp, 0, 0)) == SET)    {      if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0)))	CC_STATUS_INIT;      else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx)	{	  cc_status.flags = 0;	  cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);	  cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1);	}    }  else    CC_STATUS_INIT;  if (cc_status.value2 != 0      && ADDRESS_REG_P (cc_status.value2)      && GET_MODE (cc_status.value2) == QImode)    CC_STATUS_INIT;  if (cc_status.value2 != 0      && !(cc_status.value1 && FPA_REG_P (cc_status.value1)))    switch (GET_CODE (cc_status.value2))      {      case PLUS: case MINUS: case MULT:      case DIV: case UDIV: case MOD: case UMOD: case NEG:#if 0 /* These instructions always clear the overflow bit */      case ASHIFT: case ASHIFTRT: case LSHIFTRT:      case ROTATE: case ROTATERT:#endif	if (GET_MODE (cc_status.value2) != VOIDmode)	  cc_status.flags |= CC_NO_OVERFLOW;	break;      case ZERO_EXTEND:	/* (SET r1 (ZERO_EXTEND r2)) on this machine	   ends with a move insn moving r2 in r2's mode.	   Thus, the cc's are set for r2.	   This can set N bit spuriously. */	cc_status.flags |= CC_NOT_NEGATIVE;       default:	break;      }  if (cc_status.value1 && GET_CODE (cc_status.value1) == REG      && cc_status.value2      && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))    cc_status.value2 = 0;  if (((cc_status.value1 && FP_REG_P (cc_status.value1))       || (cc_status.value2 && FP_REG_P (cc_status.value2)))      && !((cc_status.value1 && FPA_REG_P (cc_status.value1))	   || (cc_status.value2 && FPA_REG_P (cc_status.value2))))    cc_status.flags = CC_IN_68881;}char *output_move_const_double (operands)     rtx *operands;{#ifdef SUPPORT_SUN_FPA  if (TARGET_FPA && FPA_REG_P (operands[0]))    {      int code = standard_sun_fpa_constant_p (operands[1]);      if (code != 0)	{	  static char buf[40];	  sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff);	  return buf;	}      return "fpmove%.d %1,%0";    }  else#endif    {      int code = standard_68881_constant_p (operands[1]);      if (code != 0)	{	  static char buf[40];	  sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);	  return buf;	}      return "fmove%.d %1,%0";    }}char *output_move_const_single (operands)     rtx *operands;{#ifdef SUPPORT_SUN_FPA  if (TARGET_FPA)    {      int code = standard_sun_fpa_constant_p (operands[1]);      if (code != 0)	{	  static char buf[40];	  sprintf (buf, "fp

⌨️ 快捷键说明

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