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

📄 cse.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
  ? ((((int) REG << 7) + reg_qty[REGNO (X)]) % NBUCKETS)	\  : canon_hash (X, M) % NBUCKETS)/* Determine whether register number N is considered a fixed register for CSE.   It is desirable to replace other regs with fixed regs, to reduce need for   non-fixed hard regs.   A reg wins if it is either the frame pointer or designated as fixed,   but not if it is an overlapping register.  */#ifdef OVERLAPPING_REGNO_P#define FIXED_REGNO_P(N)  \  (((N) == FRAME_POINTER_REGNUM || fixed_regs[N])	\   && ! OVERLAPPING_REGNO_P ((N)))#else#define FIXED_REGNO_P(N)  \  ((N) == FRAME_POINTER_REGNUM || fixed_regs[N])#endif/* Compute cost of X, as stored in the `cost' field of a table_elt.  Fixed   hard registers are the cheapest with a cost of 0.  Next come pseudos   with a cost of one and other hard registers with a cost of 2.  Aside   from these special cases, call `rtx_cost'.  */#define COST(X)						\  (GET_CODE (X) == REG					\   ? (REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1		\      : (FIXED_REGNO_P (REGNO (X))			\	 && REGNO_REG_CLASS (REGNO (X)) != NO_REGS) ? 0	\      : 2)						\   : rtx_cost (X, SET) * 2)/* Determine if the quantity number for register X represents a valid index   into the `qty_...' variables.  */#define REGNO_QTY_VALID_P(N) (reg_qty[N] != (N))static struct table_elt *table[NBUCKETS];/* Chain of `struct table_elt's made so far for this function   but currently removed from the table.  */static struct table_elt *free_element_chain;/* Number of `struct table_elt' structures made so far for this function.  */static int n_elements_made;/* Maximum value `n_elements_made' has had so far in this compilation   for functions previously processed.  */static int max_elements_made;/* Surviving equivalence class when two equivalence classes are merged    by recording the effects of a jump in the last insn.  Zero if the   last insn was not a conditional jump.  */static struct table_elt *last_jump_equiv_class;/* Set to the cost of a constant pool reference if one was found for a   symbolic constant.  If this was found, it means we should try to   convert constants into constant pool entries if they don't fit in   the insn.  */static int constant_pool_entries_cost;/* Bits describing what kind of values in memory must be invalidated   for a particular instruction.  If all three bits are zero,   no memory refs need to be invalidated.  Each bit is more powerful   than the preceding ones, and if a bit is set then the preceding   bits are also set.   Here is how the bits are set:   Pushing onto the stack invalidates only the stack pointer,   writing at a fixed address invalidates only variable addresses,   writing in a structure element at variable address     invalidates all but scalar variables,   and writing in anything else at variable address invalidates everything.  */struct write_data{  int sp : 1;			/* Invalidate stack pointer. */  int var : 1;			/* Invalidate variable addresses.  */  int nonscalar : 1;		/* Invalidate all but scalar variables.  */  int all : 1;			/* Invalidate all memory refs.  */};/* Nonzero if X has the form (PLUS frame-pointer integer).  We check for   virtual regs here because the simplify_*_operation routines are called   by integrate.c, which is called before virtual register instantiation.  */#define FIXED_BASE_PLUS_P(X)					\  ((X) == frame_pointer_rtx || (X) == arg_pointer_rtx		\   || (X) == virtual_stack_vars_rtx				\   || (X) == virtual_incoming_args_rtx				\   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \       && (XEXP (X, 0) == frame_pointer_rtx			\	   || XEXP (X, 0) == arg_pointer_rtx			\	   || XEXP (X, 0) == virtual_stack_vars_rtx		\	   || XEXP (X, 0) == virtual_incoming_args_rtx)))/* Similar, but also allows reference to the stack pointer.   This used to include FIXED_BASE_PLUS_P, however, we can't assume that   arg_pointer_rtx by itself is nonzero, because on at least one machine,   the i960, the arg pointer is zero when it is unused.  */#define NONZERO_BASE_PLUS_P(X)					\  ((X) == frame_pointer_rtx					\   || (X) == virtual_stack_vars_rtx				\   || (X) == virtual_incoming_args_rtx				\   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \       && (XEXP (X, 0) == frame_pointer_rtx			\	   || XEXP (X, 0) == arg_pointer_rtx			\	   || XEXP (X, 0) == virtual_stack_vars_rtx		\	   || XEXP (X, 0) == virtual_incoming_args_rtx))	\   || (X) == stack_pointer_rtx					\   || (X) == virtual_stack_dynamic_rtx				\   || (X) == virtual_outgoing_args_rtx				\   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \       && (XEXP (X, 0) == stack_pointer_rtx			\	   || XEXP (X, 0) == virtual_stack_dynamic_rtx		\	   || XEXP (X, 0) == virtual_outgoing_args_rtx)))static struct table_elt *lookup ();static void free_element ();static int insert_regs ();static void rehash_using_reg ();static void remove_invalid_refs ();static int exp_equiv_p ();int refers_to_p ();int refers_to_mem_p ();static void invalidate_from_clobbers ();static int safe_hash ();static int canon_hash ();static rtx fold_rtx ();static rtx equiv_constant ();static void record_jump_cond ();static void note_mem_written ();static int cse_rtx_addr_varies_p ();static enum rtx_code find_comparison_args ();static void cse_insn ();static void cse_set_around_loop ();/* Return an estimate of the cost of computing rtx X.   One use is in cse, to decide which expression to keep in the hash table.   Another is in rtl generation, to pick the cheapest way to multiply.   Other uses like the latter are expected in the future.  *//* Return the right cost to give to an operation   to make the cost of the corresponding register-to-register instruction   N times that of a fast register-to-register instruction.  */#define COSTS_N_INSNS(N) ((N) * 4 - 2)intrtx_cost (x, outer_code)     rtx x;     enum rtx_code outer_code;{  register int i, j;  register enum rtx_code code;  register char *fmt;  register int total;  if (x == 0)    return 0;  /* Compute the default costs of certain things.     Note that RTX_COSTS can override the defaults.  */  code = GET_CODE (x);  switch (code)    {    case MULT:      /* Count multiplication by 2**n as a shift,	 because if we are considering it, we would output it as a shift.  */      if (GET_CODE (XEXP (x, 1)) == CONST_INT	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)	total = 2;      else	total = COSTS_N_INSNS (5);      break;    case DIV:    case UDIV:    case MOD:    case UMOD:      total = COSTS_N_INSNS (7);      break;    case USE:      /* Used in loop.c and combine.c as a marker.  */      total = 0;      break;    case ASM_OPERANDS:      /* We don't want these to be used in substitutions because	 we have no way of validating the resulting insn.  So assign	 anything containing an ASM_OPERANDS a very high cost.  */      total = 1000;      break;    default:      total = 2;    }  switch (code)    {    case REG:      return 1;    case SUBREG:      /* If we can't tie these modes, make this expensive.  The larger	 the mode, the more expensive it is.  */      if (! MODES_TIEABLE_P (GET_MODE (x), GET_MODE (SUBREG_REG (x))))	return COSTS_N_INSNS (2			      + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD);      return 2;#ifdef RTX_COSTS      RTX_COSTS (x, code, outer_code);#endif       CONST_COSTS (x, code, outer_code);    }  /* Sum the costs of the sub-rtx's, plus cost of this operation,     which is already in total.  */  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    if (fmt[i] == 'e')      total += rtx_cost (XEXP (x, i), code);    else if (fmt[i] == 'E')      for (j = 0; j < XVECLEN (x, i); j++)	total += rtx_cost (XVECEXP (x, i, j), code);  return total;}/* Clear the hash table and initialize each register with its own quantity,   for a new basic block.  */static voidnew_basic_block (){  register int i;  next_qty = max_reg;  bzero (reg_tick, max_reg * sizeof (int));  bcopy (all_minus_one, reg_in_table, max_reg * sizeof (int));  bcopy (consec_ints, reg_qty, max_reg * sizeof (int));  CLEAR_HARD_REG_SET (hard_regs_in_table);  /* The per-quantity values used to be initialized here, but it is     much faster to initialize each as it is made in `make_new_qty'.  */  for (i = 0; i < NBUCKETS; i++)    {      register struct table_elt *this, *next;      for (this = table[i]; this; this = next)	{	  next = this->next_same_hash;	  free_element (this);	}    }  bzero (table, sizeof table);  prev_insn = 0;#ifdef HAVE_cc0  prev_insn_cc0 = 0;#endif}/* Say that register REG contains a quantity not in any register before   and initialize that quantity.  */static voidmake_new_qty (reg)     register int reg;{  register int q;  if (next_qty >= max_qty)    abort ();  q = reg_qty[reg] = next_qty++;  qty_first_reg[q] = reg;  qty_last_reg[q] = reg;  qty_const[q] = qty_const_insn[q] = 0;  qty_comparison_code[q] = UNKNOWN;  reg_next_eqv[reg] = reg_prev_eqv[reg] = -1;}/* Make reg NEW equivalent to reg OLD.   OLD is not changing; NEW is.  */static voidmake_regs_eqv (new, old)     register int new, old;{  register int lastr, firstr;  register int q = reg_qty[old];  /* Nothing should become eqv until it has a "non-invalid" qty number.  */  if (! REGNO_QTY_VALID_P (old))    abort ();  reg_qty[new] = q;  firstr = qty_first_reg[q];  lastr = qty_last_reg[q];  /* Prefer fixed hard registers to anything.  Prefer pseudo regs to other     hard regs.  Among pseudos, if NEW will live longer than any other reg     of the same qty, and that is beyond the current basic block,     make it the new canonical replacement for this qty.  */  if (! (firstr < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (firstr))      /* Certain fixed registers might be of the class NO_REGS.  This means	 that not only can they not be allocated by the compiler, but	 they cannot be used in substitutions or canonicalizations	 either.  */      && (new >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new) != NO_REGS)      && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new))	  || (new >= FIRST_PSEUDO_REGISTER	      && (firstr < FIRST_PSEUDO_REGISTER		  || ((uid_cuid[regno_last_uid[new]] > cse_basic_block_end		       || (uid_cuid[regno_first_uid[new]]			   < cse_basic_block_start))		      && (uid_cuid[regno_last_uid[new]]			  > uid_cuid[regno_last_uid[firstr]]))))))    {      reg_prev_eqv[firstr] = new;      reg_next_eqv[new] = firstr;      reg_prev_eqv[new] = -1;      qty_first_reg[q] = new;    }  else    {      /* If NEW is a hard reg (known to be non-fixed), insert at end.	 Otherwise, insert before any non-fixed hard regs that are at the	 end.  Registers of class NO_REGS cannot be used as an	 equivalent for anything.  */      while (lastr < FIRST_PSEUDO_REGISTER && reg_prev_eqv[lastr] >= 0	     && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr))	     && new >= FIRST_PSEUDO_REGISTER)	lastr = reg_prev_eqv[lastr];      reg_next_eqv[new] = reg_next_eqv[lastr];      if (reg_next_eqv[lastr] >= 0)	reg_prev_eqv[reg_next_eqv[lastr]] = new;      else	qty_last_reg[q] = new;      reg_next_eqv[lastr] = new;      reg_prev_eqv[new] = lastr;    }}/* Remove REG from its equivalence class.  */static voiddelete_reg_equiv (reg)     register int reg;{  register int n = reg_next_eqv[reg];  register int p = reg_prev_eqv[reg];  register int q = reg_qty[reg];  /* If invalid, do nothing.  N and P above are undefined in that case.  */  if (q == reg)    return;  if (n != -1)    reg_prev_eqv[n] = p;  else    qty_last_reg[q] = p;  if (p != -1)    reg_next_eqv[p] = n;  else    qty_first_reg[q] = n;  reg_qty[reg] = reg;}/* Remove any invalid expressions from the hash table   that refer to any of the registers contained in expression X.   Make sure that newly inserted references to those registers   as subexpressions will be considered valid.   mention_regs is not called when a register itself   is being stored in the table.   Return 1 if we have done something that may have changed the hash code   of X.  */static intmention_regs (x)     rtx x;{  register enum rtx_code code;  register int i, j;  register char *fmt;  register int changed = 0;  if (x == 0)    return 0;  code = GET_CODE (x);  if (code == REG)    {      register int regno = REGNO (x);      register int endregno	= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1		   : HARD_REGNO_NREGS (regno, GET_MODE (x)));      int i;      for (i = regno; i < endregno; i++)	{	  if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i])	    remove_invalid_refs (i);	  reg_in_table[i] = reg_tick[i];	}      return 0;    }  /* If X is a comparison or a COMPARE and either operand is a register     that does not have a quantity, give it one.  This is so that a later     call to record_jump_equiv won't cause X to be assigned a different     hash code and not found in the table after that call.     It is not necessary to do this here, since rehash_using_reg can

⌨️ 快捷键说明

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