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

📄 recog.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Subroutines used by or related to instruction recognition.   Copyright (C) 1987, 88, 91, 92, 93, 1994 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 <stdio.h>#include "insn-config.h"#include "insn-attr.h"#include "insn-flags.h"#include "insn-codes.h"#include "recog.h"#include "regs.h"#include "hard-reg-set.h"#include "flags.h"#include "real.h"#ifndef STACK_PUSH_CODE#ifdef STACK_GROWS_DOWNWARD#define STACK_PUSH_CODE PRE_DEC#else#define STACK_PUSH_CODE PRE_INC#endif#endif/* Import from final.c: */extern rtx alter_subreg ();int strict_memory_address_p ();int memory_address_p ();/* Nonzero means allow operands to be volatile.   This should be 0 if you are generating rtl, such as if you are calling   the functions in optabs.c and expmed.c (most of the time).   This should be 1 if all valid insns need to be recognized,   such as in regclass.c and final.c and reload.c.   init_recog and init_recog_no_volatile are responsible for setting this.  */int volatile_ok;/* On return from `constrain_operands', indicate which alternative   was satisfied.  */int which_alternative;/* Nonzero after end of reload pass.   Set to 1 or 0 by toplev.c.   Controls the significance of (SUBREG (MEM)).  */int reload_completed;/* Initialize data used by the function `recog'.   This must be called once in the compilation of a function   before any insn recognition may be done in the function.  */voidinit_recog_no_volatile (){  volatile_ok = 0;}voidinit_recog (){  volatile_ok = 1;}/* Try recognizing the instruction INSN,   and return the code number that results.   Remember the code so that repeated calls do not   need to spend the time for actual rerecognition.   This function is the normal interface to instruction recognition.   The automatically-generated function `recog' is normally called   through this one.  (The only exception is in combine.c.)  */intrecog_memoized (insn)     rtx insn;{  if (INSN_CODE (insn) < 0)    INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL_PTR);  return INSN_CODE (insn);}/* Check that X is an insn-body for an `asm' with operands   and that the operands mentioned in it are legitimate.  */intcheck_asm_operands (x)     rtx x;{  int noperands = asm_noperands (x);  rtx *operands;  int i;  if (noperands < 0)    return 0;  if (noperands == 0)    return 1;  operands = (rtx *) alloca (noperands * sizeof (rtx));  decode_asm_operands (x, operands, NULL_PTR, NULL_PTR, NULL_PTR);  for (i = 0; i < noperands; i++)    if (!general_operand (operands[i], VOIDmode))      return 0;  return 1;}/* Static data for the next two routines.   The maximum number of changes supported is defined as the maximum   number of operands times 5.  This allows for repeated substitutions   inside complex indexed address, or, alternatively, changes in up   to 5 insns.  */#define MAX_CHANGE_LOCS	(MAX_RECOG_OPERANDS * 5)static rtx change_objects[MAX_CHANGE_LOCS];static int change_old_codes[MAX_CHANGE_LOCS];static rtx *change_locs[MAX_CHANGE_LOCS];static rtx change_olds[MAX_CHANGE_LOCS];static int num_changes = 0;/* Validate a proposed change to OBJECT.  LOC is the location in the rtl for   at which NEW will be placed.  If OBJECT is zero, no validation is done,   the change is simply made.   Two types of objects are supported:  If OBJECT is a MEM, memory_address_p   will be called with the address and mode as parameters.  If OBJECT is   an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with   the change in place.   IN_GROUP is non-zero if this is part of a group of changes that must be   performed as a group.  In that case, the changes will be stored.  The   function `apply_change_group' will validate and apply the changes.   If IN_GROUP is zero, this is a single change.  Try to recognize the insn   or validate the memory reference with the change applied.  If the result   is not valid for the machine, suppress the change and return zero.   Otherwise, perform the change and return 1.  */intvalidate_change (object, loc, new, in_group)    rtx object;    rtx *loc;    rtx new;    int in_group;{  rtx old = *loc;  if (old == new || rtx_equal_p (old, new))    return 1;  if (num_changes >= MAX_CHANGE_LOCS      || (in_group == 0 && num_changes != 0))    abort ();  *loc = new;  /* Save the information describing this change.  */  change_objects[num_changes] = object;  change_locs[num_changes] = loc;  change_olds[num_changes] = old;  if (object && GET_CODE (object) != MEM)    {      /* Set INSN_CODE to force rerecognition of insn.  Save old code in	 case invalid.  */      change_old_codes[num_changes] = INSN_CODE (object);      INSN_CODE (object) = -1;    }  num_changes++;  /* If we are making a group of changes, return 1.  Otherwise, validate the     change group we made.  */  if (in_group)    return 1;  else    return apply_change_group ();}/* Apply a group of changes previously issued with `validate_change'.   Return 1 if all changes are valid, zero otherwise.  */intapply_change_group (){  int i;  /* The changes have been applied and all INSN_CODEs have been reset to force     rerecognition.     The changes are valid if we aren't given an object, or if we are     given a MEM and it still is a valid address, or if this is in insn     and it is recognized.  In the latter case, if reload has completed,     we also require that the operands meet the constraints for     the insn.  We do not allow modifying an ASM_OPERANDS after reload     has completed because verifying the constraints is too difficult.  */  for (i = 0; i < num_changes; i++)    {      rtx object = change_objects[i];      if (object == 0)	continue;      if (GET_CODE (object) == MEM)	{	  if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))	    break;	}      else if ((recog_memoized (object) < 0		&& (asm_noperands (PATTERN (object)) < 0		    || ! check_asm_operands (PATTERN (object))		    || reload_completed))	       || (reload_completed		   && (insn_extract (object),		       ! constrain_operands (INSN_CODE (object), 1))))	{	  rtx pat = PATTERN (object);	  /* Perhaps we couldn't recognize the insn because there were	     extra CLOBBERs at the end.  If so, try to re-recognize	     without the last CLOBBER (later iterations will cause each of	     them to be eliminated, in turn).  But don't do this if we	     have an ASM_OPERAND.  */	  if (GET_CODE (pat) == PARALLEL	      && GET_CODE (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1)) == CLOBBER	      && asm_noperands (PATTERN (object)) < 0)	    {	       rtx newpat;	       if (XVECLEN (pat, 0) == 2)		 newpat = XVECEXP (pat, 0, 0);	       else		 {		   int j;		   newpat = gen_rtx (PARALLEL, VOIDmode, 				     gen_rtvec (XVECLEN (pat, 0) - 1));		   for (j = 0; j < XVECLEN (newpat, 0); j++)		     XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);		 }	       /* Add a new change to this group to replace the pattern		  with this new pattern.  Then consider this change		  as having succeeded.  The change we added will		  cause the entire call to fail if things remain invalid.		  Note that this can lose if a later change than the one		  we are processing specified &XVECEXP (PATTERN (object), 0, X)		  but this shouldn't occur.  */	       validate_change (object, &PATTERN (object), newpat, 1);	     }	  else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)	    /* If this insn is a CLOBBER or USE, it is always valid, but is	       never recognized.  */	    continue;	  else	    break;	}    }  if (i == num_changes)    {      num_changes = 0;      return 1;    }  else    {      cancel_changes (0);      return 0;    }}/* Return the number of changes so far in the current group.   */intnum_validated_changes (){  return num_changes;}/* Retract the changes numbered NUM and up.  */voidcancel_changes (num)     int num;{  int i;  /* Back out all the changes.  Do this in the opposite order in which     they were made.  */  for (i = num_changes - 1; i >= num; i--)    {      *change_locs[i] = change_olds[i];      if (change_objects[i] && GET_CODE (change_objects[i]) != MEM)	INSN_CODE (change_objects[i]) = change_old_codes[i];    }  num_changes = num;}/* Replace every occurrence of FROM in X with TO.  Mark each change with   validate_change passing OBJECT.  */static voidvalidate_replace_rtx_1 (loc, from, to, object)     rtx *loc;     rtx from, to, object;{  register int i, j;  register char *fmt;  register rtx x = *loc;  enum rtx_code code = GET_CODE (x);  /* X matches FROM if it is the same rtx or they are both referring to the     same register in the same mode.  Avoid calling rtx_equal_p unless the     operands look similar.  */  if (x == from      || (GET_CODE (x) == REG && GET_CODE (from) == REG	  && GET_MODE (x) == GET_MODE (from)	  && REGNO (x) == REGNO (from))      || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from)	  && rtx_equal_p (x, from)))    {      validate_change (object, loc, to, 1);      return;    }  /* For commutative or comparison operations, try replacing each argument     separately and seeing if we made any changes.  If so, put a constant     argument last.*/  if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')    {      int prev_changes = num_changes;      validate_replace_rtx_1 (&XEXP (x, 0), from, to, object);      validate_replace_rtx_1 (&XEXP (x, 1), from, to, object);      if (prev_changes != num_changes && CONSTANT_P (XEXP (x, 0)))	{	  validate_change (object, loc,			   gen_rtx (GET_RTX_CLASS (code) == 'c' ? code				    : swap_condition (code),				    GET_MODE (x), XEXP (x, 1), XEXP (x, 0)),			   1);	  x = *loc;	  code = GET_CODE (x);	}    }  switch (code)    {    case PLUS:      /* If we have have a PLUS whose second operand is now a CONST_INT, use	 plus_constant to try to simplify it.  */      if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)	validate_change (object, loc, 			 plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 1);      return;          case ZERO_EXTEND:    case SIGN_EXTEND:      /* In these cases, the operation to be performed depends on the mode	 of the operand.  If we are replacing the operand with a VOIDmode	 constant, we lose the information.  So try to simplify the operation	 in that case.  If it fails, substitute in something that we know	 won't be recognized.  */      if (GET_MODE (to) == VOIDmode	  && (XEXP (x, 0) == from	      || (GET_CODE (XEXP (x, 0)) == REG && GET_CODE (from) == REG		  && GET_MODE (XEXP (x, 0)) == GET_MODE (from)		  && REGNO (XEXP (x, 0)) == REGNO (from))))	{	  rtx new = simplify_unary_operation (code, GET_MODE (x), to,					      GET_MODE (from));	  if (new == 0)	    new = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);	  validate_change (object, loc, new, 1);	  return;	}      break;	    case SUBREG:      /* If we have a SUBREG of a register that we are replacing and we are	 replacing it with a MEM, make a new MEM and try replacing the	 SUBREG with it.  Don't do this if the MEM has a mode-dependent address	 or if we would be widening it.  */      if (SUBREG_REG (x) == from	  && GET_CODE (from) == REG	  && GET_CODE (to) == MEM	  && ! mode_dependent_address_p (XEXP (to, 0))	  && ! MEM_VOLATILE_P (to)	  && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))	{	  int offset = SUBREG_WORD (x) * UNITS_PER_WORD;	  enum machine_mode mode = GET_MODE (x);	  rtx new;	  if (BYTES_BIG_ENDIAN)	    offset += (MIN (UNITS_PER_WORD,			    GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))		       - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));	  new = gen_rtx (MEM, mode, plus_constant (XEXP (to, 0), offset));	  MEM_VOLATILE_P (new) = MEM_VOLATILE_P (to);	  RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (to);	  MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (to);	  validate_change (object, loc, new, 1);	  return;	}      break;    case ZERO_EXTRACT:    case SIGN_EXTRACT:      /* If we are replacing a register with memory, try to change the memory	 to be the mode required for memory in extract operations (this isn't	 likely to be an insertion operation; if it was, nothing bad will	 happen, we might just fail in some cases).  */      if (XEXP (x, 0) == from && GET_CODE (from) == REG && GET_CODE (to) == MEM	  && GET_CODE (XEXP (x, 1)) == CONST_INT	  && GET_CODE (XEXP (x, 2)) == CONST_INT	  && ! mode_dependent_address_p (XEXP (to, 0))	  && ! MEM_VOLATILE_P (to))	{	  enum machine_mode wanted_mode = VOIDmode;	  enum machine_mode is_mode = GET_MODE (to);	  int width = INTVAL (XEXP (x, 1));	  int pos = INTVAL (XEXP (x, 2));#ifdef HAVE_extzv	  if (code == ZERO_EXTRACT)	    wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];#endif#ifdef HAVE_extv	  if (code == SIGN_EXTRACT)	    wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];#endif	  /* If we have a narrower mode, we can do something.  */	  if (wanted_mode != VOIDmode	      && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))	    {	      int offset = pos / BITS_PER_UNIT;	      rtx newmem;		  /* If the bytes and bits are counted differently, we		     must adjust the offset.  */	      if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)		offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode)			  - offset);	      pos %= GET_MODE_BITSIZE (wanted_mode);	      newmem = gen_rtx (MEM, wanted_mode,				plus_constant (XEXP (to, 0), offset));	      RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (to);	      MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (to);	      MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (to);	      validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);	      validate_change (object, &XEXP (x, 0), newmem, 1);	    }	}      break;    }      

⌨️ 快捷键说明

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