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

📄 optabs.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Expand the basic unary and binary arithmetic operations, for GNU compiler.   Copyright (C) 1987, 88, 92, 93, 94, 1995 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 2, 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, 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"#include "reload.h"#include <ctype.h>/* 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 smul_highpart_optab;optab umul_highpart_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 ior_optab;optab xor_optab;optab ashl_optab;optab lshr_optab;optab ashr_optab;optab rotl_optab;optab rotr_optab;optab smin_optab;optab smax_optab;optab umin_optab;optab umax_optab;optab mov_optab;optab movstrict_optab;optab neg_optab;optab abs_optab;optab one_cmpl_optab;optab ffs_optab;optab sqrt_optab;optab sin_optab;optab cos_optab;optab cmp_optab;optab ucmp_optab;  /* Used only for libcalls for unsigned comparisons.  */optab tst_optab;optab strlen_optab;/* Tables of patterns for extending one integer mode to another.  */enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];/* Tables of patterns for converting between fixed and floating point. */enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];/* Contains the optab used for each rtx code.  */optab code_to_optab[NUM_RTX_CODE + 1];/* SYMBOL_REF rtx's for the library functions that are called   implicitly and not via optabs.  */rtx extendsfdf2_libfunc;rtx extendsfxf2_libfunc;rtx extendsftf2_libfunc;rtx extenddfxf2_libfunc;rtx extenddftf2_libfunc;rtx truncdfsf2_libfunc;rtx truncxfsf2_libfunc;rtx trunctfsf2_libfunc;rtx truncxfdf2_libfunc;rtx trunctfdf2_libfunc;rtx memcpy_libfunc;rtx bcopy_libfunc;rtx memcmp_libfunc;rtx bcmp_libfunc;rtx memset_libfunc;rtx bzero_libfunc;rtx eqhf2_libfunc;rtx nehf2_libfunc;rtx gthf2_libfunc;rtx gehf2_libfunc;rtx lthf2_libfunc;rtx lehf2_libfunc;rtx eqsf2_libfunc;rtx nesf2_libfunc;rtx gtsf2_libfunc;rtx gesf2_libfunc;rtx ltsf2_libfunc;rtx lesf2_libfunc;rtx eqdf2_libfunc;rtx nedf2_libfunc;rtx gtdf2_libfunc;rtx gedf2_libfunc;rtx ltdf2_libfunc;rtx ledf2_libfunc;rtx eqxf2_libfunc;rtx nexf2_libfunc;rtx gtxf2_libfunc;rtx gexf2_libfunc;rtx ltxf2_libfunc;rtx lexf2_libfunc;rtx eqtf2_libfunc;rtx netf2_libfunc;rtx gttf2_libfunc;rtx getf2_libfunc;rtx lttf2_libfunc;rtx letf2_libfunc;rtx floatsisf_libfunc;rtx floatdisf_libfunc;rtx floattisf_libfunc;rtx floatsidf_libfunc;rtx floatdidf_libfunc;rtx floattidf_libfunc;rtx floatsixf_libfunc;rtx floatdixf_libfunc;rtx floattixf_libfunc;rtx floatsitf_libfunc;rtx floatditf_libfunc;rtx floattitf_libfunc;rtx fixsfsi_libfunc;rtx fixsfdi_libfunc;rtx fixsfti_libfunc;rtx fixdfsi_libfunc;rtx fixdfdi_libfunc;rtx fixdfti_libfunc;rtx fixxfsi_libfunc;rtx fixxfdi_libfunc;rtx fixxfti_libfunc;rtx fixtfsi_libfunc;rtx fixtfdi_libfunc;rtx fixtfti_libfunc;rtx fixunssfsi_libfunc;rtx fixunssfdi_libfunc;rtx fixunssfti_libfunc;rtx fixunsdfsi_libfunc;rtx fixunsdfdi_libfunc;rtx fixunsdfti_libfunc;rtx fixunsxfsi_libfunc;rtx fixunsxfdi_libfunc;rtx fixunsxfti_libfunc;rtx fixunstfsi_libfunc;rtx fixunstfdi_libfunc;rtx fixunstfti_libfunc;/* 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 insn code to make a store-condition insn   to test that condition.  */enum insn_code setcc_gen_code[NUM_RTX_CODE];#ifdef HAVE_conditional_move/* Indexed by the machine mode, gives the insn code to make a conditional   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and   setcc_gen_code to cut down on the number of named patterns.  Consider a day   when a lot more rtx codes are conditional (eg: for the ARM).  */enum insn_code movcc_gen_code[NUM_MACHINE_MODES];#endifstatic int add_equal_note	PROTO((rtx, rtx, enum rtx_code, rtx, rtx));static rtx widen_operand	PROTO((rtx, enum machine_mode,				       enum machine_mode, int, int));static enum insn_code can_fix_p	PROTO((enum machine_mode, enum machine_mode,				       int, int *));static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,					 int));static rtx ftruncify	PROTO((rtx));static optab init_optab	PROTO((enum rtx_code));static void init_libfuncs PROTO((optab, int, int, char *, int));static void init_integral_libfuncs PROTO((optab, char *, int));static void init_floating_libfuncs PROTO((optab, char *, int));static void init_complex_libfuncs PROTO((optab, char *, int));/* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to   the result of operation CODE applied to OP0 (and OP1 if it is a binary   operation).   If the last insn does not set TARGET, don't do anything, but return 1.   If a previous insn sets TARGET and TARGET is one of OP0 or OP1,   don't add the REG_EQUAL note but return 0.  Our caller can then try   again, ensuring that TARGET is not one of the operands.  */static intadd_equal_note (seq, target, code, op0, op1)     rtx seq;     rtx target;     enum rtx_code code;     rtx op0, op1;{  rtx set;  int i;  rtx note;  if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'       && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')      || GET_CODE (seq) != SEQUENCE      || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0      || GET_CODE (target) == ZERO_EXTRACT      || (! rtx_equal_p (SET_DEST (set), target)	  /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the	     SUBREG.  */	  && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART	      || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),				target))))    return 1;  /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET     besides the last insn.  */  if (reg_overlap_mentioned_p (target, op0)      || (op1 && reg_overlap_mentioned_p (target, op1)))    for (i = XVECLEN (seq, 0) - 2; i >= 0; i--)      if (reg_set_p (target, XVECEXP (seq, 0, i)))	return 0;  if (GET_RTX_CLASS (code) == '1')    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0));  else    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));  REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))    = gen_rtx (EXPR_LIST, REG_EQUAL, note,	       REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)));  return 1;}/* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP   says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need   not actually do a sign-extend or zero-extend, but can leave the    higher-order bits of the result rtx undefined, for example, in the case   of logical operations, but not right shifts.  */static rtxwiden_operand (op, mode, oldmode, unsignedp, no_extend)     rtx op;     enum machine_mode mode, oldmode;     int unsignedp;     int no_extend;{  rtx result;  /* If we must extend do so.  If OP is either a constant or a SUBREG     for a promoted object, also extend since it will be more efficient to     do so.  */  if (! no_extend      || GET_MODE (op) == VOIDmode      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)))    return convert_modes (mode, oldmode, op, unsignedp);  /* If MODE is no wider than a single word, we return a paradoxical     SUBREG.  */  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)    return gen_rtx (SUBREG, mode, force_reg (GET_MODE (op), op), 0);  /* Otherwise, get an object of MODE, clobber it, and set the low-order     part to OP.  */  result = gen_reg_rtx (mode);  emit_insn (gen_rtx (CLOBBER, VOIDmode, result));  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);  return result;}/* 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 optab_methods next_methods    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN       ? OPTAB_WIDEN : methods);  enum mode_class class;  enum machine_mode wider_mode;  register rtx temp;  int commutative_op = 0;  int shift_op = (binoptab->code ==  ASHIFT		  || binoptab->code == ASHIFTRT		  || binoptab->code == LSHIFTRT		  || binoptab->code == ROTATE		  || binoptab->code == ROTATERT);  rtx entry_last = get_last_insn ();  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 (flag_force_mem)    {      op0 = force_not_mem (op0);      op1 = force_not_mem (op1);    }  /* If subtracting an integer constant, convert this into an addition of     the negated constant.  */  if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)    {      op1 = negate_rtx (mode, op1);      binoptab = add_optab;    }  /* If we are inside an appropriately-short loop and one operand is an     expensive constant, force it into a register.  */  if (CONSTANT_P (op0) && preserve_subexpressions_p ()      && rtx_cost (op0, binoptab->code) > 2)    op0 = force_reg (mode, op0);  if (CONSTANT_P (op1) && preserve_subexpressions_p ()      && ! shift_op && rtx_cost (op1, binoptab->code) > 2)    op1 = force_reg (mode, 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 (GET_RTX_CLASS (binoptab->code) == 'c'      || binoptab == smul_widen_optab      || binoptab == umul_widen_optab      || binoptab == smul_highpart_optab      || binoptab == umul_highpart_optab)    {      commutative_op = 1;      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);      /* If it is a commutative operator and the modes would match	 if we would swap the operands, we can save the conversions. */      if (commutative_op)	{	  if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1	      && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)

⌨️ 快捷键说明

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