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

📄 optabs.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Expand the basic unary and binary arithmetic operations, for GNU compiler.   Copyright (C) 1987, 1988 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include "config.h"#include "rtl.h"#include "tree.h"#include "flags.h"#include "insn-flags.h"#include "insn-codes.h"#include "expr.h"#include "insn-config.h"#include "recog.h"/* In ANSI C we could write MODE + 1, but traditional C compilers   seem to reject it.  */#define INC_MODE(MODE) (enum machine_mode) ((int)(MODE) + 1)/* Each optab contains info on how this target machine   can perform a particular operation   for all sizes and kinds of operands.   The operation to be performed is often specified   by passing one of these optabs as an argument.   See expr.h for documentation of these optabs.  */optab add_optab;optab sub_optab;optab smul_optab;optab umul_optab;optab smul_widen_optab;optab umul_widen_optab;optab sdiv_optab;optab sdivmod_optab;optab udiv_optab;optab udivmod_optab;optab smod_optab;optab umod_optab;optab flodiv_optab;optab ftrunc_optab;optab and_optab;optab andcb_optab;optab ior_optab;optab xor_optab;optab ashl_optab;optab lshr_optab;optab lshl_optab;optab ashr_optab;optab rotl_optab;optab rotr_optab;optab mov_optab;optab movstrict_optab;optab neg_optab;optab abs_optab;optab one_cmpl_optab;optab ffs_optab;optab cmp_optab;optab ucmp_optab;  /* Used only for libcalls for unsigned comparisons.  */optab tst_optab;/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)   gives the gen_function to make a branch to test that condition.  */rtxfun bcc_gen_fctn[NUM_RTX_CODE];/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)   gives the gen_function to make a store-condition insn   to test that condition.  */rtxfun setcc_gen_fctn[NUM_RTX_CODE];/* Generate code to perform an operation specified by BINOPTAB   on operands OP0 and OP1, with result having machine-mode MODE.   UNSIGNEDP is for the case where we have to widen the operands   to perform the operation.  It says to use zero-extension.   If TARGET is nonzero, the value   is generated there, if it is convenient to do so.   In all cases an rtx is returned for the locus of the value;   this may or may not be TARGET.  */rtxexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)     enum machine_mode mode;     optab binoptab;     rtx op0, op1;     rtx target;     int unsignedp;     enum optab_methods methods;{  enum mode_class class;  enum machine_mode wider_mode;  register rtx temp;  rtx last;  class = GET_MODE_CLASS (mode);  op0 = protect_from_queue (op0, 0);  op1 = protect_from_queue (op1, 0);  if (target)    target = protect_from_queue (target, 1);#if 0  /* We may get better code by generating the result in a register     when the target is not one of the operands.  */  if (target && ! rtx_equal_p (target, op1) && ! rtx_equal_p (target, op0))    target_is_not_an_operand = 1;#endif  if (flag_force_mem)    {      op0 = force_not_mem (op0);      op1 = force_not_mem (op1);    }  /* Record where to delete back to if we backtrack.  */  last = get_last_insn ();  /* If operation is commutative,     try to make the first operand a register.     Even better, try to make it the same as the target.     Also try to make the last operand a constant.  */  if (binoptab == add_optab      || binoptab == and_optab      || binoptab == ior_optab      || binoptab == xor_optab      || binoptab == smul_optab      || binoptab == umul_optab      || binoptab == smul_widen_optab      || binoptab == umul_widen_optab)    {      if (((target == 0 || GET_CODE (target) == REG)	   ? ((GET_CODE (op1) == REG	       && GET_CODE (op0) != REG)	      || target == op1)	   : rtx_equal_p (op1, target))	  ||	  GET_CODE (op0) == CONST_INT)	{	  temp = op1;	  op1 = op0;	  op0 = temp;	}    }  /* If we can do it with a three-operand insn, do so.  */  if (methods != OPTAB_MUST_WIDEN      && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)    {      int icode = (int) binoptab->handlers[(int) mode].insn_code;      enum machine_mode mode0 = insn_operand_mode[icode][1];      enum machine_mode mode1 = insn_operand_mode[icode][2];      rtx pat;      rtx xop0 = op0, xop1 = op1;      if (target)	temp = target;      else	temp = gen_reg_rtx (mode);      /* 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)	xop0 = convert_to_mode (mode0, xop0, unsignedp);      if (GET_MODE (xop1) != VOIDmode	  && GET_MODE (xop1) != mode1)	xop1 = convert_to_mode (mode1, xop1, unsignedp);      /* Now, if insn requires register operands, put operands into regs.  */      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))	xop0 = force_reg (mode0, xop0);      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1))	xop1 = force_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)	{	  emit_insn (pat);	  return temp;	}      else	delete_insns_since (last);    }  /* It can't be open-coded in this mode.     Use a library call if one is available and caller says that's ok.  */  if (binoptab->handlers[(int) mode].lib_call      && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))    {      rtx insn_before, insn_first, insn_last;      rtx funexp = gen_rtx (SYMBOL_REF, Pmode,			    binoptab->handlers[(int) mode].lib_call);      /* Pass the address through a pseudoreg, if desired,	 before the "beginning" of the library call.	 So this insn isn't "part of" the library call, in case that	 is deleted, or cse'd.  */#ifndef NO_FUNCTION_CSE      if (! flag_no_function_cse)	funexp = copy_to_mode_reg (Pmode, funexp);#endif      insn_before = get_last_insn ();      /* Cannot pass FUNEXP since emit_library_call insists	 on getting a SYMBOL_REF.  But cse will make this SYMBOL_REF	 be replaced with the copy we made just above.  */      /* Pass 1 for NO_QUEUE so we don't lose any increments	 if the libcall is cse'd or moved.  */      emit_library_call (gen_rtx (SYMBOL_REF, Pmode,				  binoptab->handlers[(int) mode].lib_call),			 1, mode, 2, op0, mode, op1, mode);      target = hard_libcall_value (mode);      temp = copy_to_reg (target);      if (insn_before == 0)	insn_first = get_insns ();      else	insn_first = NEXT_INSN (insn_before);      insn_last = get_last_insn ();      REG_NOTES (insn_last)	= gen_rtx (EXPR_LIST, REG_EQUAL,		   gen_rtx (binoptab->code, mode, op0, op1),		   gen_rtx (INSN_LIST, REG_RETVAL, insn_first,			    REG_NOTES (insn_last)));      REG_NOTES (insn_first)	= gen_rtx (INSN_LIST, REG_LIBCALL, insn_last,		   REG_NOTES (insn_first));      return temp;    }  delete_insns_since (last);  /* It can't be done in this mode.  Can we do it in a wider mode?  */  if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN	 || methods == OPTAB_MUST_WIDEN))    return 0;			/* Caller says, don't even try.  */  /* Compute the value of METHODS to pass to recursive calls.     Don't allow widening to be tried recursively.  */  methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);  /* Widening is now independent of specific machine modes.     It is assumed that widening may be performed to any     higher numbered mode in the same mode class.  */  if (class == MODE_INT || class == MODE_FLOAT)    {      for (wider_mode = INC_MODE (mode);	   ((int) wider_mode < (int) MAX_MACHINE_MODE	    && GET_MODE_CLASS (wider_mode) == class);	   wider_mode = INC_MODE (wider_mode))	{	  if ((binoptab->handlers[(int) wider_mode].insn_code	       != CODE_FOR_nothing)	      || (methods == OPTAB_LIB		  && binoptab->handlers[(int) wider_mode].lib_call))	    {	      rtx xop0 = op0, xop1 = op1;	      int no_extend = 0;	      /* For certain 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 == andcb_optab		  || binoptab == add_optab || binoptab == sub_optab		  || binoptab == smul_optab || binoptab == umul_optab		  || binoptab == ashl_optab || binoptab == lshl_optab)		no_extend = 1;	      if (GET_MODE (xop0) != VOIDmode)		{		  if (no_extend)		    {		      temp = force_reg (GET_MODE (xop0), xop0);		      xop0 = gen_rtx (SUBREG, wider_mode, temp, 0);		    }		  else		    {		      temp = gen_reg_rtx (wider_mode);		      convert_move (temp, xop0, unsignedp);		      xop0 = temp;		    }		}	      if (GET_MODE (xop1) != VOIDmode)		{		  if (no_extend)		    {		      temp = force_reg (GET_MODE (xop1), xop1);		      xop1 = gen_rtx (SUBREG, wider_mode, temp, 0);		    }		  else		    {		      temp = gen_reg_rtx (wider_mode);		      convert_move (temp, xop1, unsignedp);		      xop1 = temp;		    }		}	      temp = expand_binop (wider_mode, binoptab, xop0, xop1, 0,				   unsignedp, methods);	      if (temp)		{		  if (class == MODE_FLOAT)		    {		      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);	    }	}    }  return 0;}/* Expand a binary operator which has both signed and unsigned forms.   UOPTAB is the optab for unsigned operations, and SOPTAB is for   signed operations.   If we widen unsigned operands, we may use a signed wider operation instead   of an unsigned wider operation, since the result would be the same.  */rtxsign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)    enum machine_mode mode;    optab uoptab, soptab;    rtx op0, op1, target;    int unsignedp;    enum optab_methods methods;{  register rtx temp;  optab direct_optab = unsignedp ? uoptab : soptab;  struct optab wide_soptab;  /* Do it without widening, if possible.  */  temp = expand_binop (mode, direct_optab, op0, op1, target,		       unsignedp, OPTAB_DIRECT);  if (temp || methods == OPTAB_DIRECT)    return temp;  /* Try widening to a signed int.  Make a fake signed optab that     hides any signed insn for direct use.  */  wide_soptab = *soptab;  wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;  wide_soptab.handlers[(int) mode].lib_call = 0;  temp = expand_binop (mode, &wide_soptab, op0, op1, target,		       unsignedp, OPTAB_WIDEN);  /* For unsigned operands, try widening to an unsigned int.  */  if (temp == 0 && unsignedp)    temp = expand_binop (mode, uoptab, op0, op1, target,			 unsignedp, OPTAB_WIDEN);  if (temp || methods == OPTAB_WIDEN)    return temp;  /* Use the right width lib call if that exists.  */  temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);  if (temp || methods == OPTAB_LIB)    return temp;  /* Must widen and use a lib call, use either signed or unsigned.  */  temp = expand_binop (mode, &wide_soptab, op0, op1, target,		       unsignedp, methods);  if (temp != 0)    return temp;  if (unsignedp)    return expand_binop (mode, uoptab, op0, op1, target,			 unsignedp, methods);  return 0;}/* Generate code to perform an operation specified by BINOPTAB   on operands OP0 and OP1, with two results to TARG1 and TARG2.   We assume that the order of the operands for the instruction   is TARG0, OP0, OP1, TARG1, which would fit a pattern like   [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].   Either TARG0 or TARG1 may be zero, but what that means is that   that result is not actually wanted.  We will generate it into   a dummy pseudo-reg and discard it.  They may not both be zero.   Returns 1 if this operation can be performed; 0 if not.  */intexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)     optab binoptab;     rtx op0, op1;     rtx targ0, targ1;     int unsignedp;{  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);  enum mode_class class;  enum machine_mode wider_mode;  class = GET_MODE_CLASS (mode);  op0 = protect_from_queue (op0, 0);  op1 = protect_from_queue (op1, 0);  if (flag_force_mem)    {      op0 = force_not_mem (op0);      op1 = force_not_mem (op1);

⌨️ 快捷键说明

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