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

📄 optabs.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
	    {	      register rtx tmp;	      tmp = op0; op0 = op1; op1 = tmp;	      tmp = xop0; xop0 = xop1; xop1 = tmp;	    }	}      /* In case the insn wants input operands in modes different from	 the result, convert the operands.  */      if (GET_MODE (op0) != VOIDmode	  && GET_MODE (op0) != mode0	  && mode0 != VOIDmode)	xop0 = convert_to_mode (mode0, xop0, unsignedp);      if (GET_MODE (xop1) != VOIDmode	  && GET_MODE (xop1) != mode1	  && mode1 != VOIDmode)	xop1 = convert_to_mode (mode1, xop1, unsignedp);      /* Now, if insn's predicates don't allow our operands, put them into	 pseudo regs.  */      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)	  && mode0 != VOIDmode)	xop0 = copy_to_mode_reg (mode0, xop0);      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)	  && mode1 != VOIDmode)	xop1 = copy_to_mode_reg (mode1, xop1);      if (! (*insn_operand_predicate[icode][0]) (temp, mode))	temp = gen_reg_rtx (mode);      pat = GEN_FCN (icode) (temp, xop0, xop1);      if (pat)	{	  /* If PAT is a multi-insn sequence, try to add an appropriate	     REG_EQUAL note to it.  If we can't because TEMP conflicts with an	     operand, call ourselves again, this time without a target.  */	  if (GET_CODE (pat) == SEQUENCE	      && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))	    {	      delete_insns_since (last);	      return expand_binop (mode, binoptab, op0, op1, NULL_RTX,				   unsignedp, methods);	    }	  emit_insn (pat);	  return temp;	}      else	delete_insns_since (last);    }  /* If this is a multiply, see if we can do a widening operation that     takes operands of this mode and makes a wider mode.  */  if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode      && (((unsignedp ? umul_widen_optab : smul_widen_optab)	   ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)	  != CODE_FOR_nothing))    {      temp = expand_binop (GET_MODE_WIDER_MODE (mode),			   unsignedp ? umul_widen_optab : smul_widen_optab,			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);      if (temp != 0)	{	  if (GET_MODE_CLASS (mode) == MODE_INT)	    return gen_lowpart (mode, temp);	  else	    return convert_to_mode (mode, temp, unsignedp);	}    }  /* Look for a wider mode of the same class for which we think we     can open-code the operation.  Check for a widening multiply at the     wider mode as well.  */  if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)      && methods != OPTAB_DIRECT && methods != OPTAB_LIB)    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))      {	if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing	    || (binoptab == smul_optab		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode		&& (((unsignedp ? umul_widen_optab : smul_widen_optab)		     ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)		    != CODE_FOR_nothing)))	  {	    rtx xop0 = op0, xop1 = op1;	    int no_extend = 0;	    /* For certain integer operations, we need not actually extend	       the narrow operands, as long as we will truncate	       the results to the same narrowness.   */	    if ((binoptab == ior_optab || binoptab == and_optab		 || binoptab == xor_optab		 || binoptab == add_optab || binoptab == sub_optab		 || binoptab == smul_optab || binoptab == ashl_optab)		&& class == MODE_INT)	      no_extend = 1;	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);	    /* The second operand of a shift must always be extended.  */	    xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,				  no_extend && binoptab != ashl_optab);	    temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,				 unsignedp, OPTAB_DIRECT);	    if (temp)	      {		if (class != MODE_INT)		  {		    if (target == 0)		      target = gen_reg_rtx (mode);		    convert_move (target, temp, 0);		    return target;		  }		else		  return gen_lowpart (mode, temp);	      }	    else	      delete_insns_since (last);	  }      }  /* These can be done a word at a time.  */  if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)      && class == MODE_INT      && GET_MODE_SIZE (mode) > UNITS_PER_WORD      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)    {      int i;      rtx insns;      rtx equiv_value;      /* If TARGET is the same as one of the operands, the REG_EQUAL note	 won't be accurate, so use a new target.  */      if (target == 0 || target == op0 || target == op1)	target = gen_reg_rtx (mode);      start_sequence ();      /* Do the actual arithmetic.  */      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)	{	  rtx target_piece = operand_subword (target, i, 1, mode);	  rtx x = expand_binop (word_mode, binoptab,				operand_subword_force (op0, i, mode),				operand_subword_force (op1, i, mode),				target_piece, unsignedp, next_methods);	  if (x == 0)	    break;	  if (target_piece != x)	    emit_move_insn (target_piece, x);	}      insns = get_insns ();      end_sequence ();      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)	{	  if (binoptab->code != UNKNOWN)	    equiv_value	      = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));	  else	    equiv_value = 0;	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);	  return target;	}    }  /* Synthesize double word shifts from single word shifts.  */  if ((binoptab == lshr_optab || binoptab == ashl_optab       || binoptab == ashr_optab)      && class == MODE_INT      && GET_CODE (op1) == CONST_INT      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)    {      rtx insns, inter, equiv_value;      rtx into_target, outof_target;      rtx into_input, outof_input;      int shift_count, left_shift, outof_word;      /* If TARGET is the same as one of the operands, the REG_EQUAL note	 won't be accurate, so use a new target.  */      if (target == 0 || target == op0 || target == op1)	target = gen_reg_rtx (mode);      start_sequence ();      shift_count = INTVAL (op1);      /* OUTOF_* is the word we are shifting bits away from, and	 INTO_* is the word that we are shifting bits towards, thus	 they differ depending on the direction of the shift and	 WORDS_BIG_ENDIAN.  */      left_shift = binoptab == ashl_optab;      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;      outof_target = operand_subword (target, outof_word, 1, mode);      into_target = operand_subword (target, 1 - outof_word, 1, mode);      outof_input = operand_subword_force (op0, outof_word, mode);      into_input = operand_subword_force (op0, 1 - outof_word, mode);      if (shift_count >= BITS_PER_WORD)	{	  inter = expand_binop (word_mode, binoptab,			       outof_input,			       GEN_INT (shift_count - BITS_PER_WORD),			       into_target, unsignedp, next_methods);	  if (inter != 0 && inter != into_target)	    emit_move_insn (into_target, inter);	  /* For a signed right shift, we must fill the word we are shifting	     out of with copies of the sign bit.  Otherwise it is zeroed.  */	  if (inter != 0 && binoptab != ashr_optab)	    inter = CONST0_RTX (word_mode);	  else if (inter != 0)	    inter = expand_binop (word_mode, binoptab,				  outof_input,				  GEN_INT (BITS_PER_WORD - 1),				  outof_target, unsignedp, next_methods);	  if (inter != 0 && inter != outof_target)	    emit_move_insn (outof_target, inter);	}      else	{	  rtx carries;	  optab reverse_unsigned_shift, unsigned_shift;	  /* For a shift of less then BITS_PER_WORD, to compute the carry,	     we must do a logical shift in the opposite direction of the	     desired shift.  */	  reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);	  /* For a shift of less than BITS_PER_WORD, to compute the word	     shifted towards, we need to unsigned shift the orig value of	     that word.  */	  unsigned_shift = (left_shift ? ashl_optab : lshr_optab);	  carries = expand_binop (word_mode, reverse_unsigned_shift,				  outof_input,				  GEN_INT (BITS_PER_WORD - shift_count),				  0, unsignedp, next_methods);	  if (carries == 0)	    inter = 0;	  else	    inter = expand_binop (word_mode, unsigned_shift, into_input,				  op1, 0, unsignedp, next_methods);	  if (inter != 0)	    inter = expand_binop (word_mode, ior_optab, carries, inter,				  into_target, unsignedp, next_methods);	  if (inter != 0 && inter != into_target)	    emit_move_insn (into_target, inter);	  if (inter != 0)	    inter = expand_binop (word_mode, binoptab, outof_input,				  op1, outof_target, unsignedp, next_methods);	  	  if (inter != 0 && inter != outof_target)	    emit_move_insn (outof_target, inter);	}      insns = get_insns ();      end_sequence ();      if (inter != 0)	{	  if (binoptab->code != UNKNOWN)	    equiv_value = gen_rtx (binoptab->code, mode, op0, op1);	  else	    equiv_value = 0;	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);	  return target;	}    }  /* Synthesize double word rotates from single word shifts.  */  if ((binoptab == rotl_optab || binoptab == rotr_optab)      && class == MODE_INT      && GET_CODE (op1) == CONST_INT      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)    {      rtx insns, equiv_value;      rtx into_target, outof_target;      rtx into_input, outof_input;      rtx inter;      int shift_count, left_shift, outof_word;      /* If TARGET is the same as one of the operands, the REG_EQUAL note	 won't be accurate, so use a new target.  */      if (target == 0 || target == op0 || target == op1)	target = gen_reg_rtx (mode);      start_sequence ();      shift_count = INTVAL (op1);      /* OUTOF_* is the word we are shifting bits away from, and	 INTO_* is the word that we are shifting bits towards, thus	 they differ depending on the direction of the shift and	 WORDS_BIG_ENDIAN.  */      left_shift = (binoptab == rotl_optab);      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;      outof_target = operand_subword (target, outof_word, 1, mode);      into_target = operand_subword (target, 1 - outof_word, 1, mode);      outof_input = operand_subword_force (op0, outof_word, mode);      into_input = operand_subword_force (op0, 1 - outof_word, mode);      if (shift_count == BITS_PER_WORD)	{	  /* This is just a word swap.  */	  emit_move_insn (outof_target, into_input);	  emit_move_insn (into_target, outof_input);	  inter = const0_rtx;	}      else	{	  rtx into_temp1, into_temp2, outof_temp1, outof_temp2;	  rtx first_shift_count, second_shift_count;	  optab reverse_unsigned_shift, unsigned_shift;	  reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)				    ? lshr_optab : ashl_optab);	  unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)			    ? ashl_optab : lshr_optab);	  if (shift_count > BITS_PER_WORD)	    {	      first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);	      second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count);	    }	  else	    {	      first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);	      second_shift_count = GEN_INT (shift_count);	    }	  into_temp1 = expand_binop (word_mode, unsigned_shift,				     outof_input, first_shift_count,				     NULL_RTX, unsignedp, next_methods);	  into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,				     into_input, second_shift_count,				     into_target, unsignedp, next_methods);	  if (into_temp1 != 0 && into_temp2 != 0)	    inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,				  into_target, unsignedp, next_methods);	  else	    inter = 0;	  if (inter != 0 && inter != into_target)	    emit_move_insn (into_target, inter);	  outof_temp1 = expand_binop (word_mode, unsigned_shift,				      into_input, first_shift_count,				      NULL_RTX, unsignedp, next_methods);	  outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,				      outof_input, second_shift_count,				      outof_target, unsignedp, next_methods);	  if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)	    inter = expand_binop (word_mode, ior_optab,				  outof_temp1, outof_temp2,				  outof_target, unsignedp, next_methods);	  if (inter != 0 && inter != outof_target)	    emit_move_insn (outof_target, inter);	}      insns = get_insns ();      end_sequence ();      if (inter != 0)	{	  if (binoptab->code != UNKNOWN)	    equiv_value = gen_rtx (binoptab->code, mode, op0, op1);	  else	    equiv_value = 0;	  /* We can't make this a no conflict block if this is a word swap,	     because the word swap case fails if the input and output values	     are in the same register.  */	  if (shift_count != BITS_PER_WORD)	    emit_no_conflict_block (insns, target, op0, op1, equiv_value);	  else	    emit_insns (insns);	  return target;	}    }  /* These can be done a word at a time by propagating carries.  */  if ((binoptab == add_optab || binoptab == sub_optab)      && class == MODE_INT      && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)    {      int i;      rtx carry_tmp = gen_reg_rtx (word_mode);      optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;      rtx carry_in, carry_out;      rtx xop0, xop1;      /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG	 value is one of those, use it.  Otherwise, use 1 since it is the	 one easiest to get.  */#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1      int normalizep = STORE_FLAG_VALUE;#else      int normalizep = 1;#endif      /* Prepare the operands.  */

⌨️ 快捷键说明

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