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

📄 expr.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Convert tree expression to rtl instructions, for GNU compiler.   Copyright (C) 1988, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include "config.h"#include "rtl.h"#include "tree.h"#include "flags.h"#include "function.h"#include "insn-flags.h"#include "insn-codes.h"#include "expr.h"#include "insn-config.h"#include "recog.h"#include "output.h"#include "gvarargs.h"#include "typeclass.h"#define CEIL(x,y) (((x) + (y) - 1) / (y))/* 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#ifndef STACK_PUSH_CODE#ifdef STACK_GROWS_DOWNWARD#define STACK_PUSH_CODE PRE_DEC#else#define STACK_PUSH_CODE PRE_INC#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.  */tree cleanups_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;rtx store_expr ();static void store_constructor ();static rtx store_field ();static rtx expand_builtin ();static rtx compare ();static rtx do_store_flag ();static void preexpand_calls ();static rtx expand_increment ();static void init_queue ();void do_pending_stack_adjust ();static void do_jump_for_compare ();static void do_jump_by_parts_equality ();static void do_jump_by_parts_equality_rtx ();static void do_jump_by_parts_greater ();/* Record for each mode whether we can move a register directly to or   from an object of that mode in memory.  If we can't, we won't try   to use that mode directly when accessing a field of that mode.  */static char direct_load[NUM_MACHINE_MODES];static char direct_store[NUM_MACHINE_MODES];/* 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) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)#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/* This array records the insn_code of insns to perform block moves.  */static enum insn_code movstr_optab[NUM_MACHINE_MODES];/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow. */#ifndef SLOW_UNALIGNED_ACCESS#define SLOW_UNALIGNED_ACCESS 0#endif/* This is run once per compilation to set up which modes can be used   directly in memory and to initialize the block move optab.  */voidinit_expr_once (){  rtx insn, pat;  enum machine_mode mode;  /* Try indexing by frame ptr and try by stack ptr.     It is known that on the Convex the stack ptr isn't a valid index.     With luck, one or the other is valid on any machine.  */  rtx mem = gen_rtx (MEM, VOIDmode, stack_pointer_rtx);  rtx mem1 = gen_rtx (MEM, VOIDmode, frame_pointer_rtx);  start_sequence ();  insn = emit_insn (gen_rtx (SET, 0, 0));  pat = PATTERN (insn);  for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;       mode = (enum machine_mode) ((int) mode + 1))    {      int regno;      rtx reg;      int num_clobbers;      direct_load[(int) mode] = direct_store[(int) mode] = 0;      PUT_MODE (mem, mode);      PUT_MODE (mem1, mode);      /* See if there is some register that can be used in this mode and	 directly loaded or stored from memory.  */      if (mode != VOIDmode && mode != BLKmode)	for (regno = 0; regno < FIRST_PSEUDO_REGISTER	     && (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0);	     regno++)	  {	    if (! HARD_REGNO_MODE_OK (regno, mode))	      continue;	    reg = gen_rtx (REG, mode, regno);	    SET_SRC (pat) = mem;	    SET_DEST (pat) = reg;	    if (recog (pat, insn, &num_clobbers) >= 0)	      direct_load[(int) mode] = 1;	    SET_SRC (pat) = mem1;	    SET_DEST (pat) = reg;	    if (recog (pat, insn, &num_clobbers) >= 0)	      direct_load[(int) mode] = 1;	    SET_SRC (pat) = reg;	    SET_DEST (pat) = mem;	    if (recog (pat, insn, &num_clobbers) >= 0)	      direct_store[(int) mode] = 1;	    SET_SRC (pat) = reg;	    SET_DEST (pat) = mem1;	    if (recog (pat, insn, &num_clobbers) >= 0)	      direct_store[(int) mode] = 1;	  }      movstr_optab[(int) mode] = CODE_FOR_nothing;    }  end_sequence ();#ifdef HAVE_movstrqi  if (HAVE_movstrqi)    movstr_optab[(int) QImode] = CODE_FOR_movstrqi;#endif#ifdef HAVE_movstrhi  if (HAVE_movstrhi)    movstr_optab[(int) HImode] = CODE_FOR_movstrhi;#endif#ifdef HAVE_movstrsi  if (HAVE_movstrsi)    movstr_optab[(int) SImode] = CODE_FOR_movstrsi;#endif#ifdef HAVE_movstrdi  if (HAVE_movstrdi)    movstr_optab[(int) DImode] = CODE_FOR_movstrdi;#endif#ifdef HAVE_movstrti  if (HAVE_movstrti)    movstr_optab[(int) TImode] = CODE_FOR_movstrti;#endif}      /* This is run at the start of compiling a function.  */voidinit_expr (){  init_queue ();  pending_stack_adjust = 0;  inhibit_defer_pop = 0;  cleanups_this_call = 0;  saveregs_value = 0;  forced_labels = 0;}/* Save all variables describing the current status into the structure *P.   This is used before starting a nested function.  */voidsave_expr_status (p)     struct function *p;{  /* Instead of saving the postincrement queue, empty it.  */  emit_queue ();  p->pending_stack_adjust = pending_stack_adjust;  p->inhibit_defer_pop = inhibit_defer_pop;  p->cleanups_this_call = cleanups_this_call;  p->saveregs_value = saveregs_value;  p->forced_labels = forced_labels;  pending_stack_adjust = 0;  inhibit_defer_pop = 0;  cleanups_this_call = 0;  saveregs_value = 0;  forced_labels = 0;}/* Restore all variables describing the current status from the structure *P.   This is used after a nested function.  */voidrestore_expr_status (p)     struct function *p;{  pending_stack_adjust = p->pending_stack_adjust;  inhibit_defer_pop = p->inhibit_defer_pop;  cleanups_this_call = p->cleanups_this_call;  saveregs_value = p->saveregs_value;  forced_labels = p->forced_labels;}/* 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, NULL_RTX, NULL_RTX, 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 0  /* A QUEUED can hang around after the queue is forced out.  */  /* Shortcut for most common case.  */  if (pending_chain == 0)    return x;#endif  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, but not	 if the value is of mode BLKmode.  */      if (code == MEM && GET_MODE (x) != BLKmode	  && 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;  enum insn_code code;  rtx libcall;  /* rtx code for making an equivalent value.  */  enum rtx_code equiv_code = (unsignedp ? ZERO_EXTEND : SIGN_EXTEND);  to = protect_from_queue (to, 1);  from = protect_from_queue (from, 0);  if (to_real != from_real)    abort ();  /* If FROM is a SUBREG that indicates that we have already done at least     the required extension, strip it.  We don't handle such SUBREGs as     TO here.  */  if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)      && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (from)))	  >= GET_MODE_SIZE (to_mode))      && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)    from = gen_lowpart (to_mode, from), from_mode = to_mode;  if (GET_CODE (to) == SUBREG && SUBREG_PROMOTED_VAR_P (to))

⌨️ 快捷键说明

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