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

📄 mips.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	  && REAL_VALUES_LESS (dflow, d))	return TRUE;    }  else    {      if (REAL_VALUES_LESS (d, sfhigh)	  && REAL_VALUES_LESS (sflow, d))	return TRUE;    }  return FALSE;}/* Accept the floating point constant 1 in the appropriate mode.  */intconst_float_1_operand (op, mode)     rtx op;     enum machine_mode mode;{  REAL_VALUE_TYPE d;  static REAL_VALUE_TYPE onedf;  static REAL_VALUE_TYPE onesf;  static int one_initialized;  if (GET_CODE (op) != CONST_DOUBLE      || mode != GET_MODE (op)      || (mode != DFmode && mode != SFmode))    return FALSE;  REAL_VALUE_FROM_CONST_DOUBLE (d, op);  /* We only initialize these values if we need them, since we will     never get called unless mips_isa >= 4.  */  if (! one_initialized)    {      onedf = REAL_VALUE_ATOF ("1.0", DFmode);      onesf = REAL_VALUE_ATOF ("1.0", SFmode);      one_initialized = TRUE;    }  if (mode == DFmode)    return REAL_VALUES_EQUAL (d, onedf);  else    return REAL_VALUES_EQUAL (d, onesf);}/* Return truth value if a memory operand fits in a single instruction   (ie, register + small offset).  */intsimple_memory_operand (op, mode)     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.  */  /* ??? This isn't strictly correct.  It is OK to accept multiword modes     here, since the length attributes are being set correctly, but only     if the address is offsettable.  LO_SUM is not offsettable.  */  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:    case LO_SUM:      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 (CONSTANT_ADDRESS_P (op)      || (GET_CODE (op) == REG && op != arg_pointer_rtx	  && ! (REGNO (op) >= FIRST_PSEUDO_REGISTER		&& REGNO (op) <= LAST_VIRTUAL_REGISTER)))    return 1;  return 0;}/* Return true if OPERAND is valid as a source operand for a move   instruction.  */intmove_operand (op, mode)     rtx op;     enum machine_mode mode;{  /* Accept any general operand after reload has started; doing so     avoids losing if reload does an in-place replacement of a register     with a SYMBOL_REF or CONST.  */  return (general_operand (op, mode)	  && (! (mips_split_addresses && mips_check_split (op, mode))	      || reload_in_progress	      || reload_completed));			}/* Return true if OPERAND is valid as a source operand for movdi.   This accepts not only general_operand, but also sign extended   constants and registers.  We need to accept sign extended constants   in case a sign extended register which is used in an expression,   and is equivalent to a constant, is spilled.  */intmovdi_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && (GET_MODE (XEXP (op, 0)) == SImode	  || (GET_CODE (XEXP (op, 0)) == CONST_INT	      && GET_MODE (XEXP (op, 0)) == VOIDmode))      && (register_operand (XEXP (op, 0), SImode)	  || immediate_operand (XEXP (op, 0), SImode)))    return 1;  return general_operand (op, mode);}/* Like register_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_register_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return register_operand (op, mode);}/* Like reg_or_0_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_reg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return reg_or_0_operand (op, mode);}/* Like uns_arith_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_uns_arith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return uns_arith_operand (op, mode);}/* Like arith_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_arith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return arith_operand (op, mode);}/* Like nonmemory_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_nonmemory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return nonmemory_operand (op, mode);}/* Like nonimmediate_operand, but when in 64 bit mode also accept a   sign extend of a 32 bit register, since the value is known to be   already sign extended.  */intse_nonimmediate_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return nonimmediate_operand (op, mode);}/* Return true if we split the address into high and low parts.  *//* ??? We should also handle reg+array somewhere.  We get four   instructions currently, lui %hi/addui %lo/addui reg/lw.  Better is   lui %hi/addui reg/lw %lo.  Fixing GO_IF_LEGITIMATE_ADDRESS to accept   (plus (reg) (symbol_ref)) doesn't work because the SYMBOL_REF is broken   out of the address, then we have 4 instructions to combine.  Perhaps   add a 3->2 define_split for combine.  *//* ??? We could also split a CONST_INT here if it is a large_int().   However, it doesn't seem to be very useful to have %hi(constant).   We would be better off by doing the masking ourselves and then putting   the explicit high part of the constant in the RTL.  This will give better   optimization.  Also, %hi(constant) needs assembler changes to work.   There is already a define_split that does this.  */intmips_check_split (address, mode)     rtx address;     enum machine_mode mode;{       /* ??? This is the same check used in simple_memory_operand.     We use it here because LO_SUM is not offsettable.  */  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)    return 0;  if ((GET_CODE (address) == SYMBOL_REF && ! SYMBOL_REF_FLAG (address))      || (GET_CODE (address) == CONST	  && GET_CODE (XEXP (XEXP (address, 0), 0)) == SYMBOL_REF	  && ! SYMBOL_REF_FLAG (XEXP (XEXP (address, 0), 0)))      || GET_CODE (address) == LABEL_REF)    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:	case LO_SUM:	  break;

⌨️ 快捷键说明

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