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

📄 expr.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Convert tree expression to rtl instructions, for GNU compiler.   Copyright (C) 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"#include "gvarargs.h"#include "typeclass.h"/* Decide whether a function's arguments should be processed   from first to last or from last to first.  */#ifdef STACK_GROWS_DOWNWARD#ifdef PUSH_ROUNDING#define PUSH_ARGS_REVERSED	/* If it's last to first */#endif#endif/* Like STACK_BOUNDARY but in units of bytes, not bits.  */#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)/* If this is nonzero, we do not bother generating VOLATILE   around volatile memory references, and we are willing to   output indirect addresses.  If cse is to follow, we reject   indirect addresses so a useful potential cse is generated;   if it is used only once, instruction combination will produce   the same indirect address eventually.  */int cse_not_expected;/* Nonzero to generate code for all the subroutines within an   expression before generating the upper levels of the expression.   Nowadays this is never zero.  */int do_preexpand_calls = 1;/* Number of units that we should eventually pop off the stack.   These are the arguments to function calls that have already returned.  */int pending_stack_adjust;/* Nonzero means stack pops must not be deferred, and deferred stack   pops must not be output.  It is nonzero inside a function call,   inside a conditional expression, inside a statement expression,   and in other cases as well.  */int inhibit_defer_pop;/* A list of all cleanups which belong to the arguments of   function calls being expanded by expand_call.  */static tree cleanups_of_this_call;/* Nonzero means __builtin_saveregs has already been done in this function.   The value is the pseudoreg containing the value __builtin_saveregs   returned.  */static rtx saveregs_value;/* Nonzero means current function may call alloca   as a subroutine.  (__builtin_alloca does not count.)  */int may_call_alloca;rtx store_expr ();static void store_constructor ();static rtx store_field ();static rtx expand_call ();static void emit_call_1 ();static rtx prepare_call_address ();static rtx expand_builtin ();static rtx compare ();static rtx compare_constants ();static rtx compare1 ();static rtx do_store_flag ();static void preexpand_calls ();static rtx expand_increment ();static void init_queue ();void do_pending_stack_adjust ();/* MOVE_RATIO is the number of move instructions that is better than   a block move.  */#ifndef MOVE_RATIO#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi)#define MOVE_RATIO 2#else/* A value of around 6 would minimize code size; infinity would minimize   execution time.  */#define MOVE_RATIO 15#endif#endif/* Table indexed by tree code giving 1 if the code is for a   comparison operation, or anything that is most easily   computed with a conditional branch.   We include tree.def to give it the proper length.   The contents thus created are irrelevant.   The real contents are initialized in init_comparisons.  */#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) 0,static char comparison_code[] = {#include "tree.def"};#undef DEFTREECODE/* This is run once per compilation.  */voidinit_comparisons (){  comparison_code[(int) EQ_EXPR] = 1;  comparison_code[(int) NE_EXPR] = 1;  comparison_code[(int) LT_EXPR] = 1;  comparison_code[(int) GT_EXPR] = 1;  comparison_code[(int) LE_EXPR] = 1;  comparison_code[(int) GE_EXPR] = 1;}/* This is run at the start of compiling a function.  */voidinit_expr (){  init_queue ();  may_call_alloca = 0;  saveregs_value = 0;}/* Manage the queue of increment instructions to be output   for POSTINCREMENT_EXPR expressions, etc.  */static rtx pending_chain;/* Queue up to increment (or change) VAR later.  BODY says how:   BODY should be the same thing you would pass to emit_insn   to increment right away.  It will go to emit_insn later on.   The value is a QUEUED expression to be used in place of VAR   where you want to guarantee the pre-incrementation value of VAR.  */static rtxenqueue_insn (var, body)     rtx var, body;{  pending_chain = gen_rtx (QUEUED, GET_MODE (var),			   var, 0, 0, body, pending_chain);  return pending_chain;}/* Use protect_from_queue to convert a QUEUED expression   into something that you can put immediately into an instruction.   If the queued incrementation has not happened yet,   protect_from_queue returns the variable itself.   If the incrementation has happened, protect_from_queue returns a temp   that contains a copy of the old value of the variable.   Any time an rtx which might possibly be a QUEUED is to be put   into an instruction, it must be passed through protect_from_queue first.   QUEUED expressions are not meaningful in instructions.   Do not pass a value through protect_from_queue and then hold   on to it for a while before putting it in an instruction!   If the queue is flushed in between, incorrect code will result.  */rtxprotect_from_queue (x, modify)     register rtx x;     int modify;{  register RTX_CODE code = GET_CODE (x);  if (code != QUEUED)    {      /* A special hack for read access to (MEM (QUEUED ...))	 to facilitate use of autoincrement.	 Make a copy of the contents of the memory location	 rather than a copy of the address.  */      if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)	{	  register rtx y = XEXP (x, 0);	  XEXP (x, 0) = QUEUED_VAR (y);	  if (QUEUED_INSN (y))	    {	      register rtx temp = gen_reg_rtx (GET_MODE (x));	      emit_insn_before (gen_move_insn (temp, x),				QUEUED_INSN (y));	      return temp;	    }	  return x;	}      /* Otherwise, recursively protect the subexpressions of all	 the kinds of rtx's that can contain a QUEUED.  */      if (code == MEM)	XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);      else if (code == PLUS || code == MULT)	{	  XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);	  XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0);	}      return x;    }  /* If the increment has not happened, use the variable itself.  */  if (QUEUED_INSN (x) == 0)    return QUEUED_VAR (x);  /* If the increment has happened and a pre-increment copy exists,     use that copy.  */  if (QUEUED_COPY (x) != 0)    return QUEUED_COPY (x);  /* The increment has happened but we haven't set up a pre-increment copy.     Set one up now, and use it.  */  QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));  emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),		    QUEUED_INSN (x));  return QUEUED_COPY (x);}/* Return nonzero if X contains a QUEUED expression:   if it contains anything that will be altered by a queued increment.   We handle only combinations of MEM, PLUS, MINUS and MULT operators   since memory addresses generally contain only those.  */static intqueued_subexp_p (x)     rtx x;{  register enum rtx_code code = GET_CODE (x);  switch (code)    {    case QUEUED:      return 1;    case MEM:      return queued_subexp_p (XEXP (x, 0));    case MULT:    case PLUS:    case MINUS:      return queued_subexp_p (XEXP (x, 0))	|| queued_subexp_p (XEXP (x, 1));    }  return 0;}/* Perform all the pending incrementations.  */voidemit_queue (){  register rtx p;  while (p = pending_chain)    {      QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));      pending_chain = QUEUED_NEXT (p);    }}static voidinit_queue (){  if (pending_chain)    abort ();}/* Copy data from FROM to TO, where the machine modes are not the same.   Both modes may be integer, or both may be floating.   UNSIGNEDP should be nonzero if FROM is an unsigned type.   This causes zero-extension instead of sign-extension.  */voidconvert_move (to, from, unsignedp)     register rtx to, from;     int unsignedp;{  enum machine_mode to_mode = GET_MODE (to);  enum machine_mode from_mode = GET_MODE (from);  int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;  int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;  int extending = (int) to_mode > (int) from_mode;  to = protect_from_queue (to, 1);  from = protect_from_queue (from, 0);  if (to_real != from_real)    abort ();  if (to_mode == from_mode      || (from_mode == VOIDmode && CONSTANT_P (from)))    {      emit_move_insn (to, from);      return;    }  if (to_real)    {#ifdef HAVE_extendsfdf2      if (HAVE_extendsfdf2 && extending)	{	  emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);	  return;	}#endif#ifdef HAVE_truncdfsf2      if (HAVE_truncdfsf2 && ! extending)	{	  emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);	  return;	}#endif      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending						      ? "__extendsfdf2"						      : "__truncdfsf2")), 0,			 GET_MODE (to), 1,			 from,  (extending ? SFmode : DFmode));      emit_move_insn (to, hard_libcall_value (GET_MODE (to)));      return;    }  /* Now both modes are integers.  */  if (to_mode == DImode)    {      if (unsignedp)	{#ifdef HAVE_zero_extendsidi2	  if (HAVE_zero_extendsidi2 && from_mode == SImode)	    emit_unop_insn (CODE_FOR_zero_extendsidi2, to, from, ZERO_EXTEND);	  else#endif#ifdef HAVE_zero_extendhidi2	  if (HAVE_zero_extendhidi2 && from_mode == HImode)	    emit_unop_insn (CODE_FOR_zero_extendhidi2, to, from, ZERO_EXTEND);	  else#endif#ifdef HAVE_zero_extendqidi2	  if (HAVE_zero_extendqidi2 && from_mode == QImode)	    emit_unop_insn (CODE_FOR_zero_extendqidi2, to, from, ZERO_EXTEND);	  else#endif#ifdef HAVE_zero_extendsidi2	  if (HAVE_zero_extendsidi2)	    {	      convert_move (gen_lowpart (SImode, to), from, unsignedp);	      emit_unop_insn (CODE_FOR_zero_extendsidi2, to,			      gen_lowpart (SImode, to), ZERO_EXTEND);	    }	  else#endif	    {	      emit_insn (gen_rtx (CLOBBER, VOIDmode, to));	      convert_move (gen_lowpart (SImode, to), from, unsignedp);	      emit_clr_insn (gen_highpart (SImode, to));	    }	}#ifdef HAVE_extendsidi2      else if (HAVE_extendsidi2 && from_mode == SImode)	emit_unop_insn (CODE_FOR_extendsidi2, to, from, SIGN_EXTEND);#endif#ifdef HAVE_extendhidi2      else if (HAVE_extendhidi2 && from_mode == HImode)	emit_unop_insn (CODE_FOR_extendhidi2, to, from, SIGN_EXTEND);#endif#ifdef HAVE_extendqidi2      else if (HAVE_extendqidi2 && from_mode == QImode)	emit_unop_insn (CODE_FOR_extendqidi2, to, from, SIGN_EXTEND);#endif#ifdef HAVE_extendsidi2      else if (HAVE_extendsidi2)	{	  convert_move (gen_lowpart (SImode, to), from, unsignedp);	  emit_unop_insn (CODE_FOR_extendsidi2, to,			  gen_lowpart (SImode, to), SIGN_EXTEND);	}#endif#ifdef HAVE_slt      else if (HAVE_slt && insn_operand_mode[(int) CODE_FOR_slt][0] == SImode)	{	  rtx temp, target;	  emit_insn (gen_rtx (CLOBBER, VOIDmode, to));	  convert_move (gen_lowpart (SImode, to), from, unsignedp);	  emit_cmp_insn (gen_lowpart (SImode, to), const0_rtx, 0, 0, 0);	  target = gen_highpart (SImode, to);	  if (!(*insn_operand_predicate[(int) CODE_FOR_slt][0]) (target, SImode))	    temp = gen_reg_rtx (SImode);	  else	    temp = target;	  emit_insn (gen_slt (temp));	  if (temp != target)	    emit_move_insn (target, temp);	}#endif      else	{	  register rtx label = gen_label_rtx ();	  rtx temp, target;	  emit_insn (gen_rtx (CLOBBER, VOIDmode, to));	  emit_clr_insn (gen_highpart (SImode, to));	  convert_move (gen_lowpart (SImode, to), from, unsignedp);	  emit_cmp_insn (gen_lowpart (SImode, to),			 gen_rtx (CONST_INT, VOIDmode, 0),			 0, 0, 0);	  NO_DEFER_POP;	  emit_jump_insn (gen_bge (label));	  target = gen_highpart (SImode, to);	  temp = expand_unop (SImode, one_cmpl_optab,			      target, gen_highpart (SImode, to),			      1);	  if (temp != target)	    emit_move_insn (target, temp);	  emit_label (label);	  OK_DEFER_POP;	}      return;    }  if (from_mode == DImode)    {      convert_move (to, gen_lowpart (SImode, from), 0);      return;    }  /* Now follow all the conversions between integers     no more than a word long.  */  /* For truncation, usually we can just refer to FROM in a narrower mode.  */  if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)      && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),				GET_MODE_BITSIZE (from_mode))      && ((GET_CODE (from) == MEM	   && ! MEM_VOLATILE_P (from)	   && ! mode_dependent_address_p (XEXP (from, 0)))	  || GET_CODE (from) == REG	  || GET_CODE (from) == SUBREG))    {      emit_move_insn (to, gen_lowpart (to_mode, from));      return;    }

⌨️ 快捷键说明

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