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

📄 mips.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
     rtx op;     enum machine_mode mode;{  rtx addr, plus0, plus1;  /* Eliminate non-memory operations */  if (GET_CODE (op) != MEM)    return FALSE;  /* dword operations really put out 2 instructions, so eliminate them.  */  if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)    return FALSE;  /* Decode the address now.  */  addr = XEXP (op, 0);  switch (GET_CODE (addr))    {    default:      break;    case REG:      return TRUE;    case CONST_INT:      return SMALL_INT (op);    case PLUS:      plus0 = XEXP (addr, 0);      plus1 = XEXP (addr, 1);      if (GET_CODE (plus0) == REG	  && GET_CODE (plus1) == CONST_INT	  && SMALL_INT (plus1))	return TRUE;      else if (GET_CODE (plus1) == REG	       && GET_CODE (plus0) == CONST_INT	       && SMALL_INT (plus0))	return TRUE;      else	return FALSE;#if 0      /* We used to allow small symbol refs here (ie, stuff in .sdata	 or .sbss), but this causes some bugs in G++.  Also, it won't	 interfere if the MIPS linker rewrites the store instruction	 because the function is PIC.  */    case LABEL_REF:		/* never gp relative */      break;    case CONST:      /* If -G 0, we can never have a GP relative memory operation.	 Also, save some time if not optimizing.  */      if (!TARGET_GP_OPT)	return FALSE;      {	rtx offset = const0_rtx;	addr = eliminate_constant_term (XEXP (addr, 0), &offset);	if (GET_CODE (op) != SYMBOL_REF)	  return FALSE;	/* let's be paranoid.... */	if (! SMALL_INT (offset))	  return FALSE;      }      /* fall through */    case SYMBOL_REF:      return SYMBOL_REF_FLAG (addr);#endif    }  return FALSE;}/* Return true if the code of this rtx pattern is EQ or NE.  */intequality_op (op, mode)     rtx op;     enum machine_mode mode;{  if (mode != GET_MODE (op))    return FALSE;  return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* Return true if the code is a relational operations (EQ, LE, etc.) */intcmp_op (op, mode)     rtx op;     enum machine_mode mode;{  if (mode != GET_MODE (op))    return FALSE;  return (GET_RTX_CLASS (GET_CODE (op)) == '<');}/* Return true if the operand is either the PC or a label_ref.  */intpc_or_label_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (op == pc_rtx)    return TRUE;  if (GET_CODE (op) == LABEL_REF)    return TRUE;  return FALSE;}/* Test for a valid operand for a call instruction.   Don't allow the arg pointer register or virtual regs   since they may change into reg + const, which the patterns   can't handle yet.  */intcall_insn_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == MEM      && (CONSTANT_ADDRESS_P (XEXP (op, 0))	  || (GET_CODE (XEXP (op, 0)) == REG	      && XEXP (op, 0) != arg_pointer_rtx	      && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER		   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))    return 1;  return 0;}/* Returns an operand string for the given instruction's delay slot,   after updating filled delay slot statistics.   We assume that operands[0] is the target register that is set.   In order to check the next insn, most of this functionality is moved   to FINAL_PRESCAN_INSN, and we just set the global variables that   it needs.  *//* ??? This function no longer does anything useful, because final_prescan_insn   now will never emit a nop.  */char *mips_fill_delay_slot (ret, type, operands, cur_insn)     char *ret;			/* normal string to return */     enum delay_type type;	/* type of delay */     rtx operands[];		/* operands to use */     rtx cur_insn;		/* current insn */{  register rtx set_reg;  register enum machine_mode mode;  register rtx next_insn	= (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0;  register int num_nops;  if (type == DELAY_LOAD || type == DELAY_FCMP)    num_nops = 1;  else if (type == DELAY_HILO)    num_nops = 2;  else    num_nops = 0;  /* Make sure that we don't put nop's after labels.  */  next_insn = NEXT_INSN (cur_insn);  while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE)    next_insn = NEXT_INSN (next_insn);  dslots_load_total += num_nops;  if (TARGET_DEBUG_F_MODE      || !optimize      || type == DELAY_NONE      || operands == (rtx *)0      || cur_insn == (rtx)0      || next_insn == (rtx)0      || GET_CODE (next_insn) == CODE_LABEL      || (set_reg = operands[0]) == (rtx)0)    {      dslots_number_nops = 0;      mips_load_reg  = (rtx)0;      mips_load_reg2 = (rtx)0;      mips_load_reg3 = (rtx)0;      mips_load_reg4 = (rtx)0;      return ret;    }  set_reg = operands[0];  if (set_reg == (rtx)0)    return ret;  while (GET_CODE (set_reg) == SUBREG)    set_reg = SUBREG_REG (set_reg);  mode = GET_MODE (set_reg);  dslots_number_nops = num_nops;  mips_load_reg = set_reg;  if (GET_MODE_SIZE (mode)      > (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD))    mips_load_reg2 = gen_rtx (REG, SImode, REGNO (set_reg) + 1);  else    mips_load_reg2 = 0;  if (type == DELAY_HILO)    {      mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);      mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);    }  else    {      mips_load_reg3 = 0;      mips_load_reg4 = 0;    }  return ret;}/* Determine whether a memory reference takes one (based off of the GP pointer),   two (normal), or three (label + reg) instructions, and bump the appropriate   counter for -mstats.  */voidmips_count_memory_refs (op, num)     rtx op;     int num;{  int additional = 0;  int n_words = 0;  rtx addr, plus0, plus1;  enum rtx_code code0, code1;  int looping;  if (TARGET_DEBUG_B_MODE)    {      fprintf (stderr, "\n========== mips_count_memory_refs:\n");      debug_rtx (op);    }  /* Skip MEM if passed, otherwise handle movsi of address.  */  addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);  /* Loop, going through the address RTL */  do    {      looping = FALSE;      switch (GET_CODE (addr))	{	default:	  break;	case REG:	case CONST_INT:	  break;	case PLUS:	  plus0 = XEXP (addr, 0);	  plus1 = XEXP (addr, 1);	  code0 = GET_CODE (plus0);	  code1 = GET_CODE (plus1);	  if (code0 == REG)	    {	      additional++;	      addr = plus1;	      looping = TRUE;	      continue;	    }	  if (code0 == CONST_INT)	    {	      addr = plus1;	      looping = TRUE;	      continue;	    }	  if (code1 == REG)	    {	      additional++;	      addr = plus0;	      looping = TRUE;	      continue;	    }	  if (code1 == CONST_INT)	    {	      addr = plus0;	      looping = TRUE;	      continue;	    }	  if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)	    {	      addr = plus0;	      looping = TRUE;	      continue;	    }	  if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)	    {	      addr = plus1;	      looping = TRUE;	      continue;	    }	  break;	case LABEL_REF:	  n_words = 2;		/* always 2 words */	  break;	case CONST:	  addr = XEXP (addr, 0);	  looping = TRUE;	  continue;	case SYMBOL_REF:	  n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;	  break;	}    }  while (looping);  if (n_words == 0)    return;  n_words += additional;  if (n_words > 3)    n_words = 3;  num_refs[n_words-1] += num;}/* Return RTL for the offset from the current function to the   argument.  */rtxembedded_pic_offset (x)     rtx x;{  if (embedded_pic_fnaddr_rtx == NULL)    {      rtx seq;      embedded_pic_fnaddr_rtx = gen_reg_rtx (Pmode);            /* Output code at function start to initialize the pseudo-reg.  */      /* ??? We used to do this in FINALIZE_PIC, but that does not work for	 inline functions, because it is called after RTL for the function	 has been copied.  The pseudo-reg in embedded_pic_fnaddr_rtx however	 does not get copied, and ends up not matching the rest of the RTL.	 This solution works, but means that we get unnecessary code to	 initialize this value every time a function is inlined into another	 function.  */      start_sequence ();      emit_insn (gen_get_fnaddr (embedded_pic_fnaddr_rtx,				 XEXP (DECL_RTL (current_function_decl), 0)));      seq = gen_sequence ();      end_sequence ();      push_topmost_sequence ();      emit_insn_after (seq, get_insns ());      pop_topmost_sequence ();    }  return gen_rtx (CONST, Pmode,		  gen_rtx (MINUS, Pmode, x,			   XEXP (DECL_RTL (current_function_decl), 0)));}/* Return the appropriate instructions to move one operand to another.  */char *mips_move_1word (operands, insn, unsignedp)     rtx operands[];     rtx insn;     int unsignedp;{  char *ret = 0;  rtx op0 = operands[0];  rtx op1 = operands[1];  enum rtx_code code0 = GET_CODE (op0);  enum rtx_code code1 = GET_CODE (op1);  enum machine_mode mode = GET_MODE (op0);  int subreg_word0 = 0;  int subreg_word1 = 0;  enum delay_type delay = DELAY_NONE;  while (code0 == SUBREG)    {      subreg_word0 += SUBREG_WORD (op0);      op0 = SUBREG_REG (op0);      code0 = GET_CODE (op0);    }  while (code1 == SUBREG)    {      subreg_word1 += SUBREG_WORD (op1);      op1 = SUBREG_REG (op1);      code1 = GET_CODE (op1);    }  if (code0 == REG)    {      int regno0 = REGNO (op0) + subreg_word0;      if (code1 == REG)	{	  int regno1 = REGNO (op1) + subreg_word1;	  /* Just in case, don't do anything for assigning a register	     to itself, unless we are filling a delay slot.  */	  if (regno0 == regno1 && set_nomacro == 0)	    ret = "";	  else if (GP_REG_P (regno0))	    {	      if (GP_REG_P (regno1))		ret = "move\t%0,%1";	      else if (MD_REG_P (regno1))		{		  delay = DELAY_HILO;		  if (regno1 != HILO_REGNUM)		    ret = "mf%1\t%0";		  else		    ret = "mflo\t%0";		}	      else		{		  delay = DELAY_LOAD;		  if (FP_REG_P (regno1))		    ret = "mfc1\t%0,%1";		  else if (regno1 == FPSW_REGNUM)		    ret = "cfc1\t%0,$31";		}	    }	  else if (FP_REG_P (regno0))	    {	      if (GP_REG_P (regno1))		{		  delay = DELAY_LOAD;		  ret = "mtc1\t%1,%0";		}	      if (FP_REG_P (regno1))		ret = "mov.s\t%0,%1";	    }	  else if (MD_REG_P (regno0))	    {	      if (GP_REG_P (regno1))		{		  delay = DELAY_HILO;		  if (regno0 != HILO_REGNUM)		    ret = "mt%0\t%1";		}	    }	  else if (regno0 == FPSW_REGNUM)	    {	      if (GP_REG_P (regno1))		{		  delay = DELAY_LOAD;		  ret = "ctc1\t%0,$31";		}	    }	}      else if (code1 == MEM)	{	  delay = DELAY_LOAD;	  if (TARGET_STATS)	    mips_count_memory_refs (op1, 1);	  if (GP_REG_P (regno0))	    {	      /* For loads, use the mode of the memory item, instead of the		 target, so zero/sign extend can use this code as well.  */	      switch (GET_MODE (op1))		{		default:		  break;		case SFmode:		  ret = "lw\t%0,%1";		  break;		case SImode:		  ret = ((unsignedp && TARGET_64BIT)			 ? "lwu\t%0,%1"			 : "lw\t%0,%1");		  break;		case HImode:		  ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1";		  break;		case QImode:		  ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1";		  break;		}	    }	  else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))	    ret = "l.s\t%0,%1";	  if (ret != (char *)0 && MEM_VOLATILE_P (op1))	    {	      int i = strlen (ret);	      if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))		abort ();

⌨️ 快捷键说明

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