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

📄 optabs.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		    != 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.  Don't do this when	       WIDER_MODE is wider than a word since a paradoxical SUBREG	       isn't valid for such modes.  */	    if ((binoptab == ior_optab || binoptab == and_optab		 || binoptab == xor_optab		 || binoptab == add_optab || binoptab == sub_optab		 || binoptab == smul_optab		 || binoptab == ashl_optab || binoptab == lshl_optab)		&& class == MODE_INT		&& GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD)	      no_extend = 1;	    /* If an operand is a constant integer, we might as well	       convert it since that is more efficient than using a SUBREG,	       unlike the case for other operands.  Similarly for	       SUBREGs that were made due to promoted objects.  */	    if (no_extend && GET_MODE (xop0) != VOIDmode		&& ! (GET_CODE (xop0) == SUBREG		      && SUBREG_PROMOTED_VAR_P (xop0)))	      xop0 = gen_rtx (SUBREG, wider_mode,			      force_reg (GET_MODE (xop0), xop0), 0);	    else	      xop0 = convert_to_mode (wider_mode, xop0, unsignedp);	    if (no_extend && GET_MODE (xop1) != VOIDmode		&& ! (GET_CODE (xop1) == SUBREG		      && SUBREG_PROMOTED_VAR_P (xop1)))	      xop1 = gen_rtx (SUBREG, wider_mode,				force_reg (GET_MODE (xop1), xop1), 0);	    else	      xop1 = convert_to_mode (wider_mode, xop1, unsignedp);	    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, methods);	  if (target_piece != x)	    emit_move_insn (target_piece, x);	}      insns = get_insns ();      end_sequence ();      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;    }  /* 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.  */      xop0 = force_reg (mode, op0);      xop1 = force_reg (mode, op1);      if (target == 0 || GET_CODE (target) != REG	  || target == xop0 || target == xop1)	target = gen_reg_rtx (mode);      /* Do the actual arithmetic.  */      for (i = 0; i < nwords; i++)	{	  int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);	  rtx target_piece = operand_subword (target, index, 1, mode);	  rtx op0_piece = operand_subword_force (xop0, index, mode);	  rtx op1_piece = operand_subword_force (xop1, index, mode);	  rtx x;	  /* Main add/subtract of the input operands.  */	  x = expand_binop (word_mode, binoptab,			    op0_piece, op1_piece,			    target_piece, unsignedp, methods);	  if (x == 0)	    break;	  if (i + 1 < nwords)	    {	      /* Store carry from main add/subtract.  */	      carry_out = gen_reg_rtx (word_mode);	      carry_out = emit_store_flag (carry_out,					   binoptab == add_optab ? LTU : GTU,					   x, op0_piece,					   word_mode, 1, normalizep);	      if (!carry_out)		break;	    }	  if (i > 0)	    {	      /* Add/subtract previous carry to main result.  */	      x = expand_binop (word_mode,				normalizep == 1 ? binoptab : otheroptab,				x, carry_in,				target_piece, 1, methods);	      if (target_piece != x)		emit_move_insn (target_piece, x);	      if (i + 1 < nwords)		{		  /* THIS CODE HAS NOT BEEN TESTED.  */		  /* Get out carry from adding/subtracting carry in.  */		  carry_tmp = emit_store_flag (carry_tmp,					       binoptab == add_optab					         ? LTU : GTU,					       x, carry_in,					       word_mode, 1, normalizep);		  /* Logical-ior the two poss. carry together.  */		  carry_out = expand_binop (word_mode, ior_optab,					    carry_out, carry_tmp,					    carry_out, 0, methods);		  if (!carry_out)		    break;		}	    }	  carry_in = carry_out;	}	      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)	{	  rtx temp;	  	  temp = emit_move_insn (target, target);	  REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,				      gen_rtx (binoptab->code, mode, xop0, xop1),				      REG_NOTES (temp));	  return target;	}      else	delete_insns_since (last);    }  /* If we want to multiply two two-word values and have normal and widening     multiplies of single-word values, we can do this with three smaller     multiplications.  Note that we do not make a REG_NO_CONFLICT block here     because we are not operating on one word at a time.      The multiplication proceeds as follows:			         _______________________			        [__op0_high_|__op0_low__]			         _______________________        *			    [__op1_high_|__op1_low__]        _______________________________________________			         _______________________    (1)			    [__op0_low__*__op1_low__]		     _______________________    (2a)		[__op0_low__*__op1_high_]		     _______________________    (2b)		[__op0_high_*__op1_low__]         _______________________    (3) [__op0_high_*__op1_high_]    This gives a 4-word result.  Since we are only interested in the    lower 2 words, partial result (3) and the upper words of (2a) and    (2b) don't need to be calculated.  Hence (2a) and (2b) can be    calculated using non-widening multiplication.    (1), however, needs to be calculated with an unsigned widening    multiplication.  If this operation is not directly supported we    try using a signed widening multiplication and adjust the result.    This adjustment works as follows:      If both operands are positive then no adjustment is needed.      If the operands have different signs, for example op0_low < 0 and      op1_low >= 0, the instruction treats the most significant bit of      op0_low as a sign bit instead of a bit with significance      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low      with 2**BITS_PER_WORD - op0_low, and two's complements the      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to      the result.      Similarly, if both operands are negative, we need to add      (op0_low + op1_low) * 2**BITS_PER_WORD.      We use a trick to adjust quickly.  We logically shift op0_low right      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to      op0_high (op1_high) before it is used to calculate 2b (2a).  If no      logical shift exists, we do an arithmetic right shift and subtract      the 0 or -1.  */  if (binoptab == smul_optab      && class == MODE_INT      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD      && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing      && ((umul_widen_optab->handlers[(int) mode].insn_code	   != CODE_FOR_nothing)	  || (smul_widen_optab->handlers[(int) mode].insn_code	      != CODE_FOR_nothing)))    {      int low = (WORDS_BIG_ENDIAN ? 1 : 0);      int high = (WORDS_BIG_ENDIAN ? 0 : 1);      rtx op0_high = operand_subword_force (op0, high, mode);      rtx op0_low = operand_subword_force (op0, low, mode);      rtx op1_high = operand_subword_force (op1, high, mode);      rtx op1_low = operand_subword_force (op1, low, mode);      rtx product = 0;      rtx op0_xhigh;      rtx op1_xhigh;      /* If the target is the same as one of the inputs, don't use it.  This	 prevents problems with the REG_EQUAL note.  */      if (target == op0 || target == op1)	target = 0;      /* Multiply the two lower words to get a double-word product.	 If unsigned widening multiplication is available, use that;	 otherwise use the signed form and compensate.  */      if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)	{	  product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,				  target, 1, OPTAB_DIRECT);	  /* If we didn't succeed, delete everything we did so far.  */	  if (product == 0)	    delete_insns_since (last);	  else	    op0_xhigh = op0_high, op1_xhigh = op1_high;	}      if (product == 0	  && smul_widen_optab->handlers[(int) mode].insn_code	       != CODE_FOR_nothing)	{	  rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);	  product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,				  target, 1, OPTAB_DIRECT);	  op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,				    NULL_RTX, 1, OPTAB_DIRECT);	  if (op0_xhigh)	    op0_xhigh = expand_binop (word_mode, add_optab, op0_high,				      op0_xhigh, op0_xhigh, 0, OPTAB_DIRECT);	  else	    {	      op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,					NULL_RTX, 0, OPTAB_DIRECT);	      if (op0_xhigh)		op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,					  op0_xhigh, op0_xhigh, 0,					  OPTAB_DIRECT);	    }	  op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,				    NULL_RTX, 1, OPTAB_DIRECT);	  if (op1_xhigh)	    op1_xhigh = expand_binop (word_mode, add_optab, op1_high,				      op1_xhigh, op1_xhigh, 0, OPTAB_DIRECT);	  else	    {	      op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,					NULL_RTX, 0, OPTAB_DIRECT);	      if (op1_xhigh)		op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,					  op1_xhigh, op1_xhigh, 0,					  OPTAB_DIRECT);	    }	}      /* If we have been able to directly compute the product of the	 low-order words of the operands and perform any required adjustments	 of the operands, we proceed by trying two more multiplications	 and then computing the appropriate sum.	 We have checked above that the required addition is provided.	 Full-word addition will normally always succeed, especially if	 it is provided at all, so we don't worry about its failure.  The	 multiplication may well fail, however, so we do handle that.  */      if (product && op0_xhigh && op1_xhigh)	{	  rtx product_piece;	  rtx product_high = operand_subword (product, high, 1, mode);	  rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,				   NULL_RTX, 0, OPTAB_DIRECT);	  if (temp)	    {	      product_piece = expand_binop (word_mode, add_optab, temp,					    product_high, product_high,					    0, OPTAB_LIB_WIDEN);	      if (product_piece != product_high)		emit_move_insn (product_high, product_piece);	      temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 				   NULL_RTX, 0, OPTAB_DIRECT);	      product_piece = expand_binop (word_mode, add_optab, temp,					    product_high, product_high,					    0, OPTAB_LIB_WIDEN);	      if (product_piece != product_high)		emit_move_insn (product_high, product_piece);	      temp = emit_move_insn (product, product);	      REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,					  gen_rtx (MULT, mode, op0, op1),					  REG_NOTES (temp));	      return product;	    }	}      /* If we get here, we couldn't do it for some reason even though we	 originally thought we could.  Delete anything we've emitted in	 trying to do it.  */      delete_insns_since (last);    }  /* We need to open-code the complex type operations: '+, -, * and /' */  /* At this point we allow operations between two similar complex     numbers, and also if one of the operands is not a complex number     but rather of MODE_FLOAT or MODE_INT. However, the caller     must make sure that the MODE of the non-complex operand matches     the SUBMODE of the complex operand.  */  if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)    {      rtx real0 = (rtx) 0;      rtx imag0 = (rtx) 0;      rtx real1 = (rtx) 0;      rtx imag1 = (rtx) 0;      rtx realr;      rtx imagr;      rtx res;      rtx seq;      rtx equiv_value;      /* Find the correct mode for the real and imaginary parts */      enum machine_mode submode	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,			 0);      if (submode == BLKmode)	abort ();      if (! target)	target = gen_reg_rtx (mode);      start_sequence ();      realr = gen_realpart  (submode, target);      imagr = gen_imagpart (submode, target);      if (GET_MODE (op0) == mode)	{	  real0 = gen_realpart  (submode, op0);	  imag0 = gen_imagpart (submode, op0);	}      else	real0 = op0;      if (GET_MODE (op1) == mode)	{	  real1 = gen_realpart  (submode, op1);	  imag1 = gen_imagpart (submode, op1);	}      else	real1 = op1;      if (! real0 || ! real1 || ! (imag0 || imag1))	abort ();      switch (binoptab->code)	{	case PLUS:	case MINUS:	  res = expand_binop (submode, binoptab, real0, real1,			      realr, unsignedp, methods);	  if (res != realr)	    emit_move_insn (realr, res);	  if (imag0 && imag1)

⌨️ 快捷键说明

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