m68k.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,431 行 · 第 1/5 页

C
2,431
字号
}/* Legitimize PIC addresses.  If the address is already   position-independent, we return ORIG.  Newly generated   position-independent addresses go to REG.  If we need more   than one register, we lose.     An address is legitimized by making an indirect reference   through the Global Offset Table with the name of the symbol   used as an offset.     The assembler and linker are responsible for placing the    address of the symbol in the GOT.  The function prologue   is responsible for initializing a5 to the starting address   of the GOT.   The assembler is also responsible for translating a symbol name   into a constant displacement from the start of the GOT.     A quick example may make things a little clearer:   When not generating PIC code to store the value 12345 into _foo   we would generate the following code:	movel #12345, _foo   When generating PIC two transformations are made.  First, the compiler   loads the address of foo into a register.  So the first transformation makes:	lea	_foo, a0	movel   #12345, a0@   The code in movsi will intercept the lea instruction and call this   routine which will transform the instructions into:	movel   a5@(_foo:w), a0	movel   #12345, a0@      That (in a nutshell) is how *all* symbol and label references are    handled.  */rtxlegitimize_pic_address (orig, mode, reg)     rtx orig, reg;     enum machine_mode mode ATTRIBUTE_UNUSED;{  rtx pic_ref = orig;  /* First handle a simple SYMBOL_REF or LABEL_REF */  if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)    {      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;      /* 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 (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;static CONST_METHOD const_method PARAMS ((rtx));#define USE_MOVQ(i)	((unsigned)((i) + 128) <= 255)static CONST_METHODconst_method (constant)     rtx constant;{  int i;  unsigned u;  i = INTVAL (constant);  if (USE_MOVQ (i))    return MOVQ;  /* The Coldfire doesn't have byte or word operations.  */  /* FIXME: This may not be useful for the m68060 either */  if (!TARGET_5200)     {      /* 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;}intconst_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 ();    }}const 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_INT (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_INT (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_INT ((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 ();    }}const char *output_move_simode_const (operands)     rtx *operands;{  if (operands[1] == const0_rtx      && (DATA_REG_P (operands[0])	  || GET_CODE (operands[0]) == MEM)      /* clr insns on 68000 read before writing.	 This isn't so on the 68010, but we have no TARGET_68010.  */      && ((TARGET_68020 || TARGET_5200)	  || !(GET_CODE (operands[0]) == MEM	       && MEM_VOLATILE_P (operands[0]))))    return "clr%.l %0";  else if (operands[1] == const0_rtx	   && ADDRESS_REG_P (operands[0]))    return "sub%.l %0,%0";  else if (DATA_REG_P (operands[0]))    return output_move_const_into_data_reg (operands);  else if (ADDRESS_REG_P (operands[0])	   && INTVAL (operands[1]) < 0x8000	   && INTVAL (operands[1]) >= -0x8000)    return "move%.w %1,%0";  else if (GET_CODE (operands[0]) == MEM      && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM	   && INTVAL (operands[1]) < 0x8000	   && INTVAL (operands[1]) >= -0x8000)    return "pea %a1";  return "move%.l %1,%0";}const char *output_move_simode (operands)     rtx *operands;{  if (GET_CODE (operands[1]) == CONST_INT)    return output_move_simode_const (operands);  else if ((GET_CODE (operands[1]) == SYMBOL_REF	    || GET_CODE (operands[1]) == CONST)	   && push_operand (operands[0], SImode))    return "pea %a1";  else if ((GET_CODE (operands[1]) == SYMBOL_REF	    || GET_CODE (operands[1]) == CONST)	   && ADDRESS_REG_P (operands[0]))    return "lea %a1,%0";  return "move%.l %1,%0";}const char *output_move_himode (operands)     rtx *operands;{ if (GET_CODE (operands[1]) == CONST_INT)    {      if (operands[1] == const0_rtx	  && (DATA_REG_P (operands[0])	      || GET_CODE (operands[0]) == MEM)	  /* clr insns on 68000 read before writing.	     This isn't so on the 68010, but we have no TARGET_68010.  */	  && ((TARGET_68020 || TARGET_5200)	      || !(GET_CODE (operands[0]) == MEM		   && MEM_VOLATILE_P (operands[0]))))	return "clr%.w %0";      else if (operands[1] == const0_rtx	       && ADDRESS_REG_P (operands[0]))	return "sub%.l %0,%0";      else if (DATA_REG_P (operands[0])	       && INTVAL (operands[1]) < 128	       && INTVAL (operands[1]) >= -128)	{#if defined(MOTOROLA) && !defined(CRDS)	  return "moveq%.l %1,%0";#else	  return "moveq %1,%0";#endif	}      else if (INTVAL (operands[1]) < 0x8000	       && INTVAL (operands[1]) >= -0x8000)	return "move%.w %1,%0";    }  else if (CONSTANT_P (operands[1]))    return "move%.l %1,%0";#ifndef SGS_NO_LI  /* Recognize the insn before a tablejump, one that refers     to a table of offsets.  Such an insn will need to refer     to a label on the insn.  So output one.  Use the label-number     of the table of offsets to generate this label.  This code,     and similar code below, assumes that there will be at most one     reference to each table.  */  if (GET_CODE (operands[1]) == MEM      && GET_CODE (XEXP (operands[1], 0)) == PLUS      && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF      && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS)    {      rtx labelref = XEXP (XEXP (operands[1], 0), 1);#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES)#ifdef SGS      asm_fprintf (asm_out_file, "\tset %LLI%d,.+2\n",		   CODE_LABEL_NUMBER (XEXP (labelref, 0)));#else /* not SGS */      asm_fprintf (asm_out_file, "\t.set %LLI%d,.+2\n",		   CODE_LABEL_NUMBER (XEXP (labelref, 0)));#endif /* not SGS */#else /* SGS_SWITCH_TABLES or not MOTOROLA */      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LI",				 CODE_LABEL_NUMBER (XEXP (labelref, 0)));#ifdef SGS_SWITCH_TABLES      /* Set flag saying we need to define the symbol	 LD%n (with value L%n-LI%n) at the end of the switch table.  */      switch_table_difference_label_flag = 1;#endif /* SGS_SWITCH_TABLES */#endif /* SGS_SWITCH_TABLES or not MOTOROLA */    }#endif /* SGS_NO_LI */  return "move%.w %1,%0";}const char *output_move_qimode (operands)     rtx *operands;{  rtx xoperands[4];  /* This is probably useless, since it loses for pushing a struct     of several bytes a byte at a time.	 */  /* 68k family always modifies the stack pointer by at least 2, even for     byte pushes.  The 5200 (coldfire) does not do this.  */  if (GET_CODE (operands[0]) == MEM      && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC      && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx      && ! ADDRESS_REG_P (operands[1])      && ! TARGET_5200)    {      xoperands[1] = operands[1];      xoperands[2]	= gen_rtx_MEM (QImode,		       gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, const1_rtx));      /* Just pushing a byte puts it in the high byte of the halfword.	*/      /* We must put it in the low-order, high-numbered byte.  */      if (!reg_mentioned_p (stack_pointer_rtx, operands[1]))	{	  xoperands[3] = stack_pointer_rtx;#ifndef NO_ADDSUB_Q	  output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands);#else	  output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands);#endif	}      else	output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands);      return "";    }  /* clr and st insns on 68000 read before writing.     This isn't so on the 68010, but we have no TARGET_68010.  */  if (!ADDRESS_REG_P (operands[0])      && ((TARGET_68020 || TARGET_5200)	  || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))    {      if (operands[1] == const0_rtx)	return "clr%.b %0";      if ((!TARGET_5200 || DATA_REG_P (operands[0]))	  && GET_CODE (operands[1]) == CONST_INT	  && (INTVAL (operands[1]) & 255) == 255)	{	  CC_STATUS_INIT;	  return "st %0";	}    }  if (GET_CODE (operands[1]) == CONST_INT      && DATA_REG_P (operands[0])      && INTVAL (operands[1]) < 128      && INTVAL (operands[1]) >= -128)    {#if defined(MOTOROLA) && !defined(CRDS)      return "moveq%.l %1,%0";#else      return "moveq %1,%0";#endif    }  if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0]))    return "sub%.l %0,%0";  if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))    return "move%.l %1,%0";  /* 68k family (including the 5200 coldfire) does not support byte moves to     from address registers.  */  if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))    return "move%.w %1,%0";  return "move%.b %1,%0";}const char *output_move_stricthi (operands)     rtx *operands;{  if (operands[1] == const0_rtx      /* clr insns on 68000 read before writing.	 This isn't so on the 68010, but we have no TARGET_68010.  */      && ((TARGET_68020 || TARGET_5200)	  || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))    return "clr%.w %0";  return "move%.w %1,%0";}const char *output_move_strictqi (operands)     rtx *operands;{  if (operands[1] == const0_rtx      /* clr insns on 68000 read before writing.         This isn't so on the 68010, but we have no TARGET_68010.  */      && ((TARGET_68020 || TARGET_5200)          || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))    return "clr%.b %0";  return "move%.b %1,%0";}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */static const 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 (GET_CODE (operands[1]) == CONST_INT)    return output_move_simode_const (operands);  return "move%.l %1,%0";}/* Output assembler code to perform a doubleword move insn   with operands OPERANDS.  */const 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 = CNS

⌨️ 快捷键说明

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