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

📄 xtensa.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
	  if (GET_CODE (offset) != CONST_INT)	    return FALSE;	  val = INTVAL (offset);	  return (val & 3) == 0 && (val >= 0 && val <= 60);	}    }  return FALSE;}intconstantpool_address_p (rtx addr){  rtx sym = addr;  if (GET_CODE (addr) == CONST)    {      rtx offset;      /* Only handle (PLUS (SYM, OFFSET)) form.  */      addr = XEXP (addr, 0);      if (GET_CODE (addr) != PLUS)	return FALSE;      /* Make sure the address is word aligned.  */      offset = XEXP (addr, 1);      if ((GET_CODE (offset) != CONST_INT)	  || ((INTVAL (offset) & 3) != 0))	return FALSE;      sym = XEXP (addr, 0);    }  if ((GET_CODE (sym) == SYMBOL_REF)      && CONSTANT_POOL_ADDRESS_P (sym))    return TRUE;  return FALSE;}intconstantpool_mem_p (rtx op){  if (GET_CODE (op) == MEM)    return constantpool_address_p (XEXP (op, 0));  return FALSE;}voidxtensa_extend_reg (rtx dst, rtx src){  rtx temp = gen_reg_rtx (SImode);  rtx shift = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (GET_MODE (src)));  /* Generate paradoxical subregs as needed so that the modes match.  */  src = simplify_gen_subreg (SImode, src, GET_MODE (src), 0);  dst = simplify_gen_subreg (SImode, dst, GET_MODE (dst), 0);  emit_insn (gen_ashlsi3 (temp, src, shift));  emit_insn (gen_ashrsi3 (dst, temp, shift));}boolxtensa_mem_offset (unsigned v, enum machine_mode mode){  switch (mode)    {    case BLKmode:      /* Handle the worst case for block moves.  See xtensa_expand_block_move	 where we emit an optimized block move operation if the block can be	 moved in < "move_ratio" pieces.  The worst case is when the block is	 aligned but has a size of (3 mod 4) (does this happen?) so that the	 last piece requires a byte load/store.  */      return (xtensa_uimm8 (v)	      && xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));    case QImode:      return xtensa_uimm8 (v);    case HImode:      return xtensa_uimm8x2 (v);    case DFmode:      return (xtensa_uimm8x4 (v) && xtensa_uimm8x4 (v + 4));    default:      break;    }  return xtensa_uimm8x4 (v);}boolxtensa_extra_constraint (rtx op, int c){  /* Allow pseudo registers during reload.  */  if (GET_CODE (op) != MEM)    return (c >= 'R' && c <= 'U'	    && reload_in_progress && GET_CODE (op) == REG	    && REGNO (op) >= FIRST_PSEUDO_REGISTER);  switch (c)    {    case 'R': return smalloffset_mem_p (op);    case 'T': return !TARGET_CONST16 && constantpool_mem_p (op);    case 'U': return !constantpool_mem_p (op);    default: break;    }  return false;}/* Make normal rtx_code into something we can index from an array.  */static enum internal_testmap_test_to_internal_test (enum rtx_code test_code){  enum internal_test test = ITEST_MAX;  switch (test_code)    {    default:			break;    case EQ:  test = ITEST_EQ;  break;    case NE:  test = ITEST_NE;  break;    case GT:  test = ITEST_GT;  break;    case GE:  test = ITEST_GE;  break;    case LT:  test = ITEST_LT;  break;    case LE:  test = ITEST_LE;  break;    case GTU: test = ITEST_GTU; break;    case GEU: test = ITEST_GEU; break;    case LTU: test = ITEST_LTU; break;    case LEU: test = ITEST_LEU; break;    }  return test;}/* Generate the code to compare two integer values.  The return value is   the comparison expression.  */static rtxgen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */		    rtx cmp0, /* first operand to compare */		    rtx cmp1, /* second operand to compare */		    int *p_invert /* whether branch needs to reverse test */){  struct cmp_info  {    enum rtx_code test_code;	/* test code to use in insn */    bool (*const_range_p) (HOST_WIDE_INT); /* range check function */    int const_add;		/* constant to add (convert LE -> LT) */    int reverse_regs;		/* reverse registers in test */    int invert_const;		/* != 0 if invert value if cmp1 is constant */    int invert_reg;		/* != 0 if invert value if cmp1 is register */    int unsignedp;		/* != 0 for unsigned comparisons.  */  };  static struct cmp_info info[ (int)ITEST_MAX ] = {    { EQ,	xtensa_b4const_or_zero,	0, 0, 0, 0, 0 },	/* EQ  */    { NE,	xtensa_b4const_or_zero,	0, 0, 0, 0, 0 },	/* NE  */    { LT,	xtensa_b4const_or_zero,	1, 1, 1, 0, 0 },	/* GT  */    { GE,	xtensa_b4const_or_zero,	0, 0, 0, 0, 0 },	/* GE  */    { LT,	xtensa_b4const_or_zero,	0, 0, 0, 0, 0 },	/* LT  */    { GE,	xtensa_b4const_or_zero,	1, 1, 1, 0, 0 },	/* LE  */    { LTU,	xtensa_b4constu,	1, 1, 1, 0, 1 },	/* GTU */    { GEU,	xtensa_b4constu,	0, 0, 0, 0, 1 },	/* GEU */    { LTU,	xtensa_b4constu,	0, 0, 0, 0, 1 },	/* LTU */    { GEU,	xtensa_b4constu,	1, 1, 1, 0, 1 },	/* LEU */  };  enum internal_test test;  enum machine_mode mode;  struct cmp_info *p_info;  test = map_test_to_internal_test (test_code);  gcc_assert (test != ITEST_MAX);  p_info = &info[ (int)test ];  mode = GET_MODE (cmp0);  if (mode == VOIDmode)    mode = GET_MODE (cmp1);  /* Make sure we can handle any constants given to us.  */  if (GET_CODE (cmp1) == CONST_INT)    {      HOST_WIDE_INT value = INTVAL (cmp1);      unsigned HOST_WIDE_INT uvalue = (unsigned HOST_WIDE_INT)value;      /* if the immediate overflows or does not fit in the immediate field,	 spill it to a register */      if ((p_info->unsignedp ?	   (uvalue + p_info->const_add > uvalue) :	   (value + p_info->const_add > value)) != (p_info->const_add > 0))	{	  cmp1 = force_reg (mode, cmp1);	}      else if (!(p_info->const_range_p) (value + p_info->const_add))	{	  cmp1 = force_reg (mode, cmp1);	}    }  else if ((GET_CODE (cmp1) != REG) && (GET_CODE (cmp1) != SUBREG))    {      cmp1 = force_reg (mode, cmp1);    }  /* See if we need to invert the result.  */  *p_invert = ((GET_CODE (cmp1) == CONST_INT)	       ? p_info->invert_const	       : p_info->invert_reg);  /* Comparison to constants, may involve adding 1 to change a LT into LE.     Comparison between two registers, may involve switching operands.  */  if (GET_CODE (cmp1) == CONST_INT)    {      if (p_info->const_add != 0)	cmp1 = GEN_INT (INTVAL (cmp1) + p_info->const_add);    }  else if (p_info->reverse_regs)    {      rtx temp = cmp0;      cmp0 = cmp1;      cmp1 = temp;    }  return gen_rtx_fmt_ee (p_info->test_code, VOIDmode, cmp0, cmp1);}/* Generate the code to compare two float values.  The return value is   the comparison expression.  */static rtxgen_float_relational (enum rtx_code test_code, /* relational test (EQ, etc) */		      rtx cmp0, /* first operand to compare */		      rtx cmp1 /* second operand to compare */){  rtx (*gen_fn) (rtx, rtx, rtx);  rtx brtmp;  int reverse_regs, invert;  switch (test_code)    {    case EQ: reverse_regs = 0; invert = 0; gen_fn = gen_seq_sf; break;    case NE: reverse_regs = 0; invert = 1; gen_fn = gen_seq_sf; break;    case LE: reverse_regs = 0; invert = 0; gen_fn = gen_sle_sf; break;    case GT: reverse_regs = 1; invert = 0; gen_fn = gen_slt_sf; break;    case LT: reverse_regs = 0; invert = 0; gen_fn = gen_slt_sf; break;    case GE: reverse_regs = 1; invert = 0; gen_fn = gen_sle_sf; break;    default:      fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));      reverse_regs = 0; invert = 0; gen_fn = 0; /* avoid compiler warnings */    }  if (reverse_regs)    {      rtx temp = cmp0;      cmp0 = cmp1;      cmp1 = temp;    }  brtmp = gen_rtx_REG (CCmode, FPCC_REGNUM);  emit_insn (gen_fn (brtmp, cmp0, cmp1));  return gen_rtx_fmt_ee (invert ? EQ : NE, VOIDmode, brtmp, const0_rtx);}voidxtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code){  enum cmp_type type = branch_type;  rtx cmp0 = branch_cmp[0];  rtx cmp1 = branch_cmp[1];  rtx cmp;  int invert;  rtx label1, label2;  switch (type)    {    case CMP_DF:    default:      fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));    case CMP_SI:      invert = FALSE;      cmp = gen_int_relational (test_code, cmp0, cmp1, &invert);      break;    case CMP_SF:      if (!TARGET_HARD_FLOAT)	fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));      invert = FALSE;      cmp = gen_float_relational (test_code, cmp0, cmp1);      break;    }  /* Generate the branch.  */  label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]);  label2 = pc_rtx;  if (invert)    {      label2 = label1;      label1 = pc_rtx;    }  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,			       gen_rtx_IF_THEN_ELSE (VOIDmode, cmp,						     label1,						     label2)));}static rtxgen_conditional_move (rtx cmp){  enum rtx_code code = GET_CODE (cmp);  rtx op0 = branch_cmp[0];  rtx op1 = branch_cmp[1];  if (branch_type == CMP_SI)    {      /* Jump optimization calls get_condition() which canonicalizes	 comparisons like (GE x <const>) to (GT x <const-1>).	 Transform those comparisons back to GE, since that is the	 comparison supported in Xtensa.  We shouldn't have to	 transform <LE x const> comparisons, because neither	 xtensa_expand_conditional_branch() nor get_condition() will	 produce them.  */      if ((code == GT) && (op1 == constm1_rtx))	{	  code = GE;	  op1 = const0_rtx;	}      cmp = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);      if (boolean_operator (cmp, VOIDmode))	{	  /* Swap the operands to make const0 second.  */	  if (op0 == const0_rtx)	    {	      op0 = op1;	      op1 = const0_rtx;	    }	  /* If not comparing against zero, emit a comparison (subtract).  */	  if (op1 != const0_rtx)	    {	      op0 = expand_binop (SImode, sub_optab, op0, op1,				  0, 0, OPTAB_LIB_WIDEN);	      op1 = const0_rtx;	    }	}      else if (branch_operator (cmp, VOIDmode))	{	  /* Swap the operands to make const0 second.  */	  if (op0 == const0_rtx)	    {	      op0 = op1;	      op1 = const0_rtx;	      switch (code)		{		case LT: code = GE; break;		case GE: code = LT; break;		default: gcc_unreachable ();		}	    }	  if (op1 != const0_rtx)	    return 0;	}      else	return 0;      return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);    }  if (TARGET_HARD_FLOAT && (branch_type == CMP_SF))    return gen_float_relational (code, op0, op1);  return 0;}intxtensa_expand_conditional_move (rtx *operands, int isflt){  rtx cmp;  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);  if (!(cmp = gen_conditional_move (operands[1])))    return 0;  if (isflt)    gen_fn = (branch_type == CMP_SI	      ? gen_movsfcc_internal0	      : gen_movsfcc_internal1);  else    gen_fn = (branch_type == CMP_SI	      ? gen_movsicc_internal0	      : gen_movsicc_internal1);  emit_insn (gen_fn (operands[0], XEXP (cmp, 0),		     operands[2], operands[3], cmp));  return 1;}intxtensa_expand_scc (rtx *operands){  rtx dest = operands[0];  rtx cmp = operands[1];  rtx one_tmp, zero_tmp;  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);  if (!(cmp = gen_conditional_move (cmp)))    return 0;  one_tmp = gen_reg_rtx (SImode);  zero_tmp = gen_reg_rtx (SImode);  emit_insn (gen_movsi (one_tmp, const_true_rtx));  emit_insn (gen_movsi (zero_tmp, const0_rtx));  gen_fn = (branch_type == CMP_SI	    ? gen_movsicc_internal0	    : gen_movsicc_internal1);  emit_insn (gen_fn (dest, XEXP (cmp, 0), one_tmp, zero_tmp, cmp));  return 1;}/* Split OP[1] into OP[2,3] and likewise for OP[0] into OP[0,1].  MODE is   for the output, i.e., the input operands are twice as big as MODE.  */voidxtensa_split_operand_pair (rtx operands[4], enum machine_mode mode){  switch (GET_CODE (operands[1]))    {    case REG:      operands[3] = gen_rtx_REG (mode, REGNO (operands[1]) + 1);      operands[2] = gen_rtx_REG (mode, REGNO (operands[1]));      break;    case MEM:      operands[3] = adjust_address (operands[1], mode, GET_MODE_SIZE (mode));      operands[2] = adjust_address (operands[1], mode, 0);      break;    case CONST_INT:    case CONST_DOUBLE:      split_double (operands[1], &operands[2], &operands[3]);      break;    default:      gcc_unreachable ();    }  switch (GET_CODE (operands[0]))    {    case REG:      operands[1] = gen_rtx_REG (mode, REGNO (operands[0]) + 1);      operands[0] = gen_rtx_REG (mode, REGNO (operands[0]));      break;    case MEM:      operands[1] = adjust_address (operands[0], mode, GET_MODE_SIZE (mode));      operands[0] = adjust_address (operands[0], mode, 0);      break;

⌨️ 快捷键说明

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