This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

CSE data structure cleanup



This patch replaces the group of per-qty and per-register
seperate arrays into unified structured arrays.

This generally cleans up some of CSE, decreases the amount
of malloc/free calls, and potentially speeds up CSE due to
increased data reference locality.

This change was successfully bootstrapped and produced
no regressions compared to before the change for a
sparc-unknown-linux-gnu native build.

Does anyone see anything wrong with checking this in?
If not, I'll begin to perform similar surgery in other
areas of the compiler which have the same issue.

Thanks.

1999-11-29  David S. Miller  <davem@redhat.com>

	Move quantity tables and register equivalence chains into
	per-qty and per-register structure arrays respectively.
	* cse.c (qty_first_reg, qty_last_reg, qty_mode, qty_const,
	qty_const_insn, qty_comparison_code, qty_comparison_const,
	qty_comparison_qty): Delete, replace with...
	(qty_table): this structure table.
	(reg_next_eqv, reg_prev_eqv): Delete, replace with...
	(reg_eqv_table): this structure table.
	(make_new_qty): Add argument MODE.  Caller updated.
	Update to use qty_table and reg_eqv_table.
	(make_regs_eqv, delete_reg_equiv, insert_regs,
	insert, exp_equiv_p, cse_rtx_varies_p, canon_reg,
	fold_rtx, equiv_constant, record_jump_cond, cse_insn,
	cse_process_notes, cse_main, cse_basic_block): Likewise.
	
--- cse.c.~1~	Sat Nov 20 15:17:17 1999
+++ cse.c	Mon Nov 29 00:22:22 1999
@@ -55,8 +55,8 @@ Boston, MA 02111-1307, USA.  */
    optimizer after CSE to delete the unreachable code.
 
    We use two data structures to record the equivalent expressions:
-   a hash table for most expressions, and several vectors together
-   with "quantity numbers" to record equivalent (pseudo) registers.
+   a hash table for most expressions, and a vector of "quantity
+   numbers" to record equivalent (pseudo) registers.
 
    The use of the special data structure for registers is desirable
    because it is faster.  It is possible because registers references
@@ -81,19 +81,19 @@ Registers and "quantity numbers":
    All real quantity numbers are greater than or equal to `max_reg'.
    If register N has not been assigned a quantity, reg_qty[N] will equal N.
 
-   Quantity numbers below `max_reg' do not exist and none of the `qty_...'
-   variables should be referenced with an index below `max_reg'.
+   Quantity numbers below `max_reg' do not exist and none of the `qty_table'
+   entries should be referenced with an index below `max_reg'.
 
    We also maintain a bidirectional chain of registers for each
-   quantity number.  `qty_first_reg', `qty_last_reg',
-   `reg_next_eqv' and `reg_prev_eqv' hold these chains.
+   quantity number.  The `qty_table` members `first_reg' and `last_reg',
+   and `reg_eqv_table' members `next' and `prev' hold these chains.
 
    The first register in a chain is the one whose lifespan is least local.
    Among equals, it is the one that was seen first.
    We replace any equivalent register with that one.
 
    If two registers have the same quantity number, it must be true that
-   REG expressions with `qty_mode' must be in the hash table for both
+   REG expressions with qty_table `mode' must be in the hash table for both
    registers and must be in the same class.
 
    The converse is not true.  Since hard registers may be referenced in
@@ -104,7 +104,7 @@ Registers and "quantity numbers":
 Constants and quantity numbers
 
    When a quantity has a known constant value, that value is stored
-   in the appropriate element of qty_const.  This is in addition to
+   in the appropriate qty_table `const_rtx'.  This is in addition to
    putting the constant in the hash table as is usual for non-regs.
 
    Whether a reg or a constant is preferred is determined by the configuration
@@ -112,8 +112,8 @@ Constants and quantity numbers
    event, expressions containing constants can be simplified, by fold_rtx.
 
    When a quantity has a known nearly constant value (such as an address
-   of a stack slot), that value is stored in the appropriate element
-   of qty_const.
+   of a stack slot), that value is stored in the appropriate qty_table
+   `const_rtx'.
 
    Integer constants don't have a machine mode.  However, cse
    determines the intended machine mode from the destination
@@ -133,7 +133,7 @@ Other expressions:
    currently have equivalent values.
 
    Register references in an expression are canonicalized before hashing
-   the expression.  This is done using `reg_qty' and `qty_first_reg'.
+   the expression.  This is done using `reg_qty' and qty_table `first_reg'.
    The hash code of a register reference is computed using the quantity
    number, not the register number.
 
@@ -205,8 +205,8 @@ static int max_reg;
 
 static int max_insn_uid;
 
-/* Length of vectors indexed by quantity number.
-   We know in advance we will not need a quantity number this big.  */
+/* Length of qty_table vector.  We know in advance we will not need
+   a quantity number this big.  */
 
 static int max_qty;
 
@@ -215,48 +215,48 @@ static int max_qty;
 
 static int next_qty;
 
-/* Indexed by quantity number, gives the first (or last) register 
-   in the chain of registers that currently contain this quantity.  */
-
-static int *qty_first_reg;
-static int *qty_last_reg;
-
-/* Index by quantity number, gives the mode of the quantity.  */
-
-static enum machine_mode *qty_mode;
-
-/* Indexed by quantity number, gives the rtx of the constant value of the
-   quantity, or zero if it does not have a known value.
-   A sum of the frame pointer (or arg pointer) plus a constant
-   can also be entered here.  */
-
-static rtx *qty_const;
-
-/* Indexed by qty number, gives the insn that stored the constant value
-   recorded in `qty_const'.  */
-
-static rtx *qty_const_insn;
-
-/* The next three variables are used to track when a comparison between a
-   quantity and some constant or register has been passed.  In that case, we
-   know the results of the comparison in case we see it again.  These variables
-   record a comparison that is known to be true.  */
-
-/* Indexed by qty number, gives the rtx code of a comparison with a known
-   result involving this quantity.  If none, it is UNKNOWN.  */
-static enum rtx_code *qty_comparison_code;
-
-/* Indexed by qty number, gives the constant being compared against in a
-   comparison of known result.  If no such comparison, it is undefined.
-   If the comparison is not with a constant, it is zero.  */
+/* Per-qty information tracking.  */
+struct qty_table_elem
+{
+  /* The first (or last) register in the chain of registers that
+     currently contain this quantity.  */
+  int first_reg, last_reg;
 
-static rtx *qty_comparison_const;
+  /* The mode of the quantity.  */
+  enum machine_mode mode;
 
-/* Indexed by qty number, gives the quantity being compared against in a
-   comparison of known result.  If no such comparison, if it undefined.
-   If the comparison is not with a register, it is -1.  */
+  /* The rtx of the constant value of the quantity, or zero if
+     it does not have a known value.  A sum of the frame pointer
+     (or arg pointer) plus a constant can also be entered here.  */
+  rtx const_rtx;
+
+  /* The insn that stored the constant value recorded in
+     `const_rtx'.  */
+  rtx const_insn;
+
+  /* The next three members are used to track when a comparison
+     between a quantity and some constant or register has been
+     passed.  In that case, we know the results of the comparison
+     in case we see it again.  These variables record a comparison
+     that is known to be true.  */
+
+  /* The rtx code of a comparison with a known result involving this
+     quantity.  If none, it is UNKNOWN.  */
+  enum rtx_code comparison_code;
+
+  /* The constant being compared against in a comparison of known result.
+     If no such comparison, it is undefined.  If the comparison is not
+     with a constant, it is zero.  */
+  rtx comparison_const;
+
+  /* The quantity being compared against in a comparison of known result.
+     If no such comparison, if it undefined.  If the comparison is not
+     with a register, it is -1.  */
+  int comparison_qty;
+};
 
-static int *qty_comparison_qty;
+/* The table of all qtys, indexed by qty number.  */
+static struct qty_table_elem *qty_table;
 
 #ifdef HAVE_cc0
 /* For machines that have a CC0, we do not record its value in the hash
@@ -286,10 +286,16 @@ static rtx this_insn;
 
    Or -1 if this register is at the end of the chain.
 
-   If reg_qty[N] == N, reg_next_eqv[N] is undefined.  */
+   If reg_qty[N] == N, reg_eqv_table[N].next is undefined.  */
+
+/* Per-register equivalence chain.  */
+struct reg_eqv_elem
+{
+  int next, prev;
+};
 
-static int *reg_next_eqv;
-static int *reg_prev_eqv;
+/* The table of all register equivalence chains.  */
+static struct reg_eqv_elem *reg_eqv_table;
 
 struct cse_reg_info
 {
@@ -519,7 +525,7 @@ struct table_elt
 #define REG_QTY(N) ((GET_CSE_REG_INFO (N))->reg_qty)
 
 /* Determine if the quantity number for register X represents a valid index
-   into the `qty_...' variables.  */
+   into the qty_table.  */
 
 #define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (N))
 
@@ -643,7 +649,7 @@ struct cse_basic_block_data
 
 static int notreg_cost		PROTO((rtx));
 static void new_basic_block	PROTO((void));
-static void make_new_qty	PROTO((int));
+static void make_new_qty	PROTO((int, enum machine_mode));
 static void make_regs_eqv	PROTO((int, int));
 static void delete_reg_equiv	PROTO((int));
 static int mention_regs		PROTO((rtx));
@@ -950,25 +956,31 @@ new_basic_block ()
 #endif
 }
 
-/* Say that register REG contains a quantity not in any register before
-   and initialize that quantity.  */
+/* Say that register REG contains a quantity in mode MODE not in any
+   register before and initialize that quantity.  */
 
 static void
-make_new_qty (reg)
+make_new_qty (reg, mode)
      register int reg;
+     register enum machine_mode mode;
 {
   register int q;
+  register struct qty_table_elem *ent;
+  register struct reg_eqv_elem *eqv;
 
   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;
+  ent = &qty_table[q];
+  ent->first_reg = reg;
+  ent->last_reg = reg;
+  ent->mode = mode;
+  ent->const_rtx = ent->const_insn = NULL_RTX;
+  ent->comparison_code = UNKNOWN;
 
-  reg_next_eqv[reg] = reg_prev_eqv[reg] = -1;
+  eqv = &reg_eqv_table[reg];
+  eqv->next = eqv->prev = -1;
 }
 
 /* Make reg NEW equivalent to reg OLD.
@@ -980,14 +992,17 @@ make_regs_eqv (new, old)
 {
   register int lastr, firstr;
   register int q = REG_QTY (old);
+  register struct qty_table_elem *ent;
+
+  ent = &qty_table[q];
 
   /* 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];
+  firstr = ent->first_reg;
+  lastr = ent->last_reg;
 
   /* Prefer fixed hard registers to anything.  Prefer pseudo regs to other
      hard regs.  Among pseudos, if NEW will live longer than any other reg
@@ -1008,10 +1023,10 @@ make_regs_eqv (new, old)
 		      && (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;
+      reg_eqv_table[firstr].prev = new;
+      reg_eqv_table[new].next = firstr;
+      reg_eqv_table[new].prev = -1;
+      ent->first_reg = new;
     }
   else
     {
@@ -1019,17 +1034,17 @@ make_regs_eqv (new, old)
 	 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
+      while (lastr < FIRST_PSEUDO_REGISTER && reg_eqv_table[lastr].prev >= 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;
+	lastr = reg_eqv_table[lastr].prev;
+      reg_eqv_table[new].next = reg_eqv_table[lastr].next;
+      if (reg_eqv_table[lastr].next >= 0)
+	reg_eqv_table[reg_eqv_table[lastr].next].prev = new;
       else
-	qty_last_reg[q] = new;
-      reg_next_eqv[lastr] = new;
-      reg_prev_eqv[new] = lastr;
+	qty_table[q].last_reg = new;
+      reg_eqv_table[lastr].next = new;
+      reg_eqv_table[new].prev = lastr;
     }
 }
 
@@ -1039,6 +1054,7 @@ static void
 delete_reg_equiv (reg)
      register int reg;
 {
+  register struct qty_table_elem *ent;
   register int q = REG_QTY (reg);
   register int p, n;
 
@@ -1046,17 +1062,19 @@ delete_reg_equiv (reg)
   if (q == reg)
     return;
 
-  p = reg_prev_eqv[reg];
-  n = reg_next_eqv[reg];
+  ent = &qty_table[q];
+
+  p = reg_eqv_table[reg].prev;
+  n = reg_eqv_table[reg].next;
 
   if (n != -1)
-    reg_prev_eqv[n] = p;
+    reg_eqv_table[n].prev = p;
   else
-    qty_last_reg[q] = p;
+    ent->last_reg = p;
   if (p != -1)
-    reg_next_eqv[p] = n;
+    reg_eqv_table[p].next = n;
   else
-    qty_first_reg[q] = n;
+    ent->first_reg = n;
 
   REG_QTY (reg) = reg;
 }
@@ -1188,15 +1206,21 @@ insert_regs (x, classp, modified)
   if (GET_CODE (x) == REG)
     {
       register int regno = REGNO (x);
+      register int qty_valid;
 
       /* If REGNO is in the equivalence table already but is of the
 	 wrong mode for that equivalence, don't do anything here.  */
 
-      if (REGNO_QTY_VALID_P (regno)
-	  && qty_mode[REG_QTY (regno)] != GET_MODE (x))
-	return 0;
+      qty_valid = REGNO_QTY_VALID_P (regno);
+      if (qty_valid)
+	{
+	  struct qty_table_elem *ent = &qty_table[REG_QTY (regno)];
+
+	  if (ent->mode != GET_MODE (x))
+	    return 0;
+	}
 
-      if (modified || ! REGNO_QTY_VALID_P (regno))
+      if (modified || ! qty_valid)
 	{
 	  if (classp)
 	    for (classp = classp->first_same_value;
@@ -1209,8 +1233,7 @@ insert_regs (x, classp, modified)
 		  return 1;
 		}
 
-	  make_new_qty (regno);
-	  qty_mode[REG_QTY (regno)] = GET_MODE (x);
+	  make_new_qty (regno, GET_MODE (x));
 	  return 1;
 	}
 
@@ -1566,18 +1589,22 @@ insert (x, classp, hash, mode)
      constant, we must check the entire class.
 
      If this is a register that is already known equivalent to an insn,
-     update `qty_const_insn' to show that `this_insn' is the latest
+     update the qtys `const_insn' to show that `this_insn' is the latest
      insn making that quantity equivalent to the constant.  */
 
   if (elt->is_const && classp && GET_CODE (classp->exp) == REG
       && GET_CODE (x) != REG)
     {
-      qty_const[REG_QTY (REGNO (classp->exp))]
-	= gen_lowpart_if_possible (qty_mode[REG_QTY (REGNO (classp->exp))], x);
-      qty_const_insn[REG_QTY (REGNO (classp->exp))] = this_insn;
+      int exp_q = REG_QTY (REGNO (classp->exp));
+      struct qty_table_elem *exp_ent = &qty_table[exp_q];
+
+      exp_ent->const_rtx = gen_lowpart_if_possible (exp_ent->mode, x);
+      exp_ent->const_insn = this_insn;
     }
 
-  else if (GET_CODE (x) == REG && classp && ! qty_const[REG_QTY (REGNO (x))]
+  else if (GET_CODE (x) == REG
+	   && classp
+	   && ! qty_table[REG_QTY (REGNO (x))].const_rtx
 	   && ! elt->is_const)
     {
       register struct table_elt *p;
@@ -1586,17 +1613,20 @@ insert (x, classp, hash, mode)
 	{
 	  if (p->is_const && GET_CODE (p->exp) != REG)
 	    {
-	      qty_const[REG_QTY (REGNO (x))]
-		= gen_lowpart_if_possible (GET_MODE (x), p->exp);
-	      qty_const_insn[REG_QTY (REGNO (x))] = this_insn;
+	      int x_q = REG_QTY (REGNO (x));
+	      struct qty_table_elem *x_ent = &qty_table[x_q];
+
+	      x_ent->const_rtx = gen_lowpart_if_possible (GET_MODE (x), p->exp);
+	      x_ent->const_insn = this_insn;
 	      break;
 	    }
 	}
     }
 
-  else if (GET_CODE (x) == REG && qty_const[REG_QTY (REGNO (x))]
-	   && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))])
-    qty_const_insn[REG_QTY (REGNO (x))] = this_insn;
+  else if (GET_CODE (x) == REG
+	   && qty_table[REG_QTY (REGNO (x))].const_rtx
+	   && GET_MODE (x) == qty_table[REG_QTY (REGNO (x))].mode)
+    qty_table[REG_QTY (REGNO (x))].const_insn = this_insn;
 
   /* If this is a constant with symbolic value,
      and it has a term with an explicit integer value,
@@ -2321,17 +2351,27 @@ exp_equiv_p (x, y, validate, equal_value
       /* If X is a constant and Y is a register or vice versa, they may be
 	 equivalent.  We only have to validate if Y is a register.  */
       if (CONSTANT_P (x) && GET_CODE (y) == REG
-	  && REGNO_QTY_VALID_P (REGNO (y))
-	  && GET_MODE (y) == qty_mode[REG_QTY (REGNO (y))]
-	  && rtx_equal_p (x, qty_const[REG_QTY (REGNO (y))])
-	  && (! validate || REG_IN_TABLE (REGNO (y)) == REG_TICK (REGNO (y))))
-	return 1;
+	  && REGNO_QTY_VALID_P (REGNO (y)))
+	{
+	  int y_q = REG_QTY (REGNO (y));
+	  struct qty_table_elem *y_ent = &qty_table[y_q];
+
+	  if (GET_MODE (y) == y_ent->mode
+	      && rtx_equal_p (x, y_ent->const_rtx)
+	      && (! validate || REG_IN_TABLE (REGNO (y)) == REG_TICK (REGNO (y))))
+	    return 1;
+	}
 
       if (CONSTANT_P (y) && code == REG
-	  && REGNO_QTY_VALID_P (REGNO (x))
-	  && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))]
-	  && rtx_equal_p (y, qty_const[REG_QTY (REGNO (x))]))
-	return 1;
+	  && REGNO_QTY_VALID_P (REGNO (x)))
+	{
+	  int x_q = REG_QTY (REGNO (x));
+	  struct qty_table_elem *x_ent = &qty_table[x_q];
+
+	  if (GET_MODE (x) == x_ent->mode
+	      && rtx_equal_p (y, x_ent->const_rtx))
+	    return 1;
+	}
 
       return 0;
     }
@@ -2462,19 +2502,28 @@ cse_rtx_varies_p (x)
      doesn't vary in any mode.  */
 
   if (GET_CODE (x) == REG
-      && REGNO_QTY_VALID_P (REGNO (x))
-      && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))]
-      && qty_const[REG_QTY (REGNO (x))] != 0)
-    return 0;
+      && REGNO_QTY_VALID_P (REGNO (x)))
+    {
+      int x_q = REG_QTY (REGNO (x));
+      struct qty_table_elem *x_ent = &qty_table[x_q];
+
+      if (GET_MODE (x) == x_ent->mode
+	  && x_ent->const_rtx != NULL_RTX)
+	return 0;
+    }
 
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && GET_CODE (XEXP (x, 0)) == REG
-      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
-      && (GET_MODE (XEXP (x, 0))
-	  == qty_mode[REG_QTY (REGNO (XEXP (x, 0)))])
-      && qty_const[REG_QTY (REGNO (XEXP (x, 0)))])
-    return 0;
+      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
+    {
+      int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
+      struct qty_table_elem *x0_ent = &qty_table[x0_q];
+
+      if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
+	  && x0_ent->const_rtx != NULL_RTX)
+	return 0;
+    }
 
   /* This can happen as the result of virtual register instantiation, if
      the initial constant is too large to be a valid address.  This gives
@@ -2485,14 +2534,19 @@ cse_rtx_varies_p (x)
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == REG
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
-      && (GET_MODE (XEXP (x, 0))
-	  == qty_mode[REG_QTY (REGNO (XEXP (x, 0)))])
-      && qty_const[REG_QTY (REGNO (XEXP (x, 0)))]
-      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))
-      && (GET_MODE (XEXP (x, 1))
-	  == qty_mode[REG_QTY (REGNO (XEXP (x, 1)))])
-      && qty_const[REG_QTY (REGNO (XEXP (x, 1)))])
-    return 0;
+      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
+    {
+      int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
+      int x1_q = REG_QTY (REGNO (XEXP (x, 1)));
+      struct qty_table_elem *x0_ent = &qty_table[x0_q];
+      struct qty_table_elem *x1_ent = &qty_table[x1_q];
+
+      if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
+	  && x0_ent->const_rtx != NULL_RTX
+	  && (GET_MODE (XEXP (x, 1)) == x1_ent->mode)
+	  && x1_ent->const_rtx != NULL_RTX)
+	return 0;
+    }
 
   return rtx_varies_p (x);
 }
@@ -2537,6 +2591,8 @@ canon_reg (x, insn)
     case REG:
       {
 	register int first;
+	register int q;
+	register struct qty_table_elem *ent;
 
 	/* Never replace a hard reg, because hard regs can appear
 	   in more than one machine mode, and we must preserve the mode
@@ -2547,10 +2603,12 @@ canon_reg (x, insn)
 	    || ! REGNO_QTY_VALID_P (REGNO (x)))
 	  return x;
 
-	first = qty_first_reg[REG_QTY (REGNO (x))];
+	q = REG_QTY (REGNO(x));
+	ent = &qty_table[q];
+	first = ent->first_reg;
 	return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
 		: REGNO_REG_CLASS (first) == NO_REGS ? x
-		: gen_rtx_REG (qty_mode[REG_QTY (REGNO (x))], first));
+		: gen_rtx_REG (ent->mode, first));
       }
       
     default:
@@ -3105,7 +3163,7 @@ fold_rtx (x, insn)
 		    && GET_MODE (SUBREG_REG (elt->exp)) == mode
 		    && exp_equiv_p (elt->exp, elt->exp, 1, 0))
 		  return copy_rtx (SUBREG_REG (elt->exp));
-	    }
+	      }
 
 	  return x;
 	}
@@ -3279,10 +3337,15 @@ fold_rtx (x, insn)
 	HOST_WIDE_INT offset = 0;
 
 	if (GET_CODE (addr) == REG
-	    && REGNO_QTY_VALID_P (REGNO (addr))
-	    && GET_MODE (addr) == qty_mode[REG_QTY (REGNO (addr))]
-	    && qty_const[REG_QTY (REGNO (addr))] != 0)
-	  addr = qty_const[REG_QTY (REGNO (addr))];
+	    && REGNO_QTY_VALID_P (REGNO (addr)))
+	  {
+	    int addr_q = REG_QTY (REGNO (addr));
+	    struct qty_table_elem *addr_ent = &qty_table[addr_q];
+
+	    if (GET_MODE (addr) == addr_ent->mode
+		&& addr_ent->const_rtx != NULL_RTX)
+	      addr = addr_ent->const_rtx;
+	  }
 
 	/* If address is constant, split it into a base and integer offset.  */
 	if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
@@ -3423,13 +3486,18 @@ fold_rtx (x, insn)
 	  case REG:
 	    /* This is the same as calling equiv_constant; it is duplicated
 	       here for speed.  */
-	    if (REGNO_QTY_VALID_P (REGNO (arg))
-		&& qty_const[REG_QTY (REGNO (arg))] != 0
-		&& GET_CODE (qty_const[REG_QTY (REGNO (arg))]) != REG
-		&& GET_CODE (qty_const[REG_QTY (REGNO (arg))]) != PLUS)
-	      const_arg
-		= gen_lowpart_if_possible (GET_MODE (arg),
-					   qty_const[REG_QTY (REGNO (arg))]);
+	    if (REGNO_QTY_VALID_P (REGNO (arg)))
+	      {
+		int arg_q = REG_QTY (REGNO (arg));
+		struct qty_table_elem *arg_ent = &qty_table[arg_q];
+
+		if (arg_ent->const_rtx != NULL_RTX
+		    && GET_CODE (arg_ent->const_rtx) != REG
+		    && GET_CODE (arg_ent->const_rtx) != PLUS)
+		  const_arg
+		    = gen_lowpart_if_possible (GET_MODE (arg),
+					       arg_ent->const_rtx);
+	      }
 	    break;
 
 	  case CONST:
@@ -3672,21 +3740,23 @@ fold_rtx (x, insn)
 		{
 		  int qty = REG_QTY (REGNO (folded_arg0));
 
-		  if (REGNO_QTY_VALID_P (REGNO (folded_arg0))
-		      && (comparison_dominates_p (qty_comparison_code[qty], code)
-			  || (comparison_dominates_p (qty_comparison_code[qty],
-						      reverse_condition (code))
-			      && ! FLOAT_MODE_P (mode_arg0)))
-		      && (rtx_equal_p (qty_comparison_const[qty], folded_arg1)
-			  || (const_arg1
-			      && rtx_equal_p (qty_comparison_const[qty],
-					      const_arg1))
-			  || (GET_CODE (folded_arg1) == REG
-			      && (REG_QTY (REGNO (folded_arg1))
-				  == qty_comparison_qty[qty]))))
-		    return (comparison_dominates_p (qty_comparison_code[qty],
-						    code)
-			    ? true : false);
+		  if (REGNO_QTY_VALID_P (REGNO (folded_arg0)))
+		    {
+		      struct qty_table_elem *ent = &qty_table[qty];
+
+		      if ((comparison_dominates_p (ent->comparison_code, code)
+			   || (comparison_dominates_p (ent->comparison_code,
+						       reverse_condition (code))
+			       && ! FLOAT_MODE_P (mode_arg0)))
+			  && (rtx_equal_p (ent->comparison_const, folded_arg1)
+			      || (const_arg1
+				  && rtx_equal_p (ent->comparison_const,
+						  const_arg1))
+			      || (GET_CODE (folded_arg1) == REG
+				  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
+			return (comparison_dominates_p (ent->comparison_code, code)
+				? true : false);
+		    }
 		}
 	    }
 	}
@@ -3984,9 +4054,14 @@ equiv_constant (x)
      rtx x;
 {
   if (GET_CODE (x) == REG
-      && REGNO_QTY_VALID_P (REGNO (x))
-      && qty_const[REG_QTY (REGNO (x))])
-    x = gen_lowpart_if_possible (GET_MODE (x), qty_const[REG_QTY (REGNO (x))]);
+      && REGNO_QTY_VALID_P (REGNO (x)))
+    {
+      int x_q = REG_QTY (REGNO (x));
+      struct qty_table_elem *x_ent = &qty_table[x_q];
+
+      if (x_ent->const_rtx)
+	x = gen_lowpart_if_possible (GET_MODE (x), x_ent->const_rtx);
+    }
 
   if (x == 0 || CONSTANT_P (x))
     return x;
@@ -4229,6 +4304,9 @@ record_jump_cond (code, mode, op0, op1, 
 
   if (code != EQ || FLOAT_MODE_P (GET_MODE (op0)))
     {
+      struct qty_table_elem *ent;
+      int qty;
+
       /* If we reversed a floating-point comparison, if OP0 is not a
 	 register, or if OP1 is neither a register or constant, we can't
 	 do anything.  */
@@ -4260,7 +4338,10 @@ record_jump_cond (code, mode, op0, op1, 
 	  op0_elt->in_memory = op0_in_memory;
 	}
 
-      qty_comparison_code[REG_QTY (REGNO (op0))] = code;
+      qty = REG_QTY (REGNO (op0));
+      ent = &qty_table[qty];
+
+      ent->comparison_code = code;
       if (GET_CODE (op1) == REG)
 	{
 	  /* Look it up again--in case op0 and op1 are the same.  */
@@ -4279,13 +4360,13 @@ record_jump_cond (code, mode, op0, op1, 
 	      op1_elt->in_memory = op1_in_memory;
 	    }
 
-	  qty_comparison_qty[REG_QTY (REGNO (op0))] = REG_QTY (REGNO (op1));
-	  qty_comparison_const[REG_QTY (REGNO (op0))] = 0;
+	  ent->comparison_const = NULL_RTX;
+	  ent->comparison_qty = REG_QTY (REGNO (op1));
 	}
       else
 	{
-	  qty_comparison_qty[REG_QTY (REGNO (op0))] = -1;
-	  qty_comparison_const[REG_QTY (REGNO (op0))] = op1;
+	  ent->comparison_const = op1;
+	  ent->comparison_qty = -1;
 	}
 
       return;
@@ -5198,36 +5279,43 @@ cse_insn (insn, libcall_insn)
 	 both registers live over a portion of the basic block.  This way,
 	 their lifetimes will likely abut instead of overlapping.  */
       if (GET_CODE (dest) == REG
-	  && REGNO_QTY_VALID_P (REGNO (dest))
-	  && qty_mode[REG_QTY (REGNO (dest))] == GET_MODE (dest)
-	  && qty_first_reg[REG_QTY (REGNO (dest))] != REGNO (dest)
-	  && GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
-	  /* Don't do this if the original insn had a hard reg as
-	     SET_SRC or SET_DEST.  */
-	  && (GET_CODE (sets[i].src) != REG
-	      || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
-	  && (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
-	/* We can't call canon_reg here because it won't do anything if
-	   SRC is a hard register.  */
-	{
-	  int first = qty_first_reg[REG_QTY (REGNO (src))];
-	  rtx new_src
-	    = (first >= FIRST_PSEUDO_REGISTER
-	       ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
-
-	  /* We must use validate-change even for this, because this
-	     might be a special no-op instruction, suitable only to
-	     tag notes onto.  */
-	  if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
-	    {
-	      src = new_src;
-	      /* If we had a constant that is cheaper than what we are now
-		 setting SRC to, use that constant.  We ignored it when we
-		 thought we could make this into a no-op.  */
-	      if (src_const && COST (src_const) < COST (src)
-		  && validate_change (insn, &SET_SRC (sets[i].rtl), src_const,
-				      0))
-		src = src_const;
+	  && REGNO_QTY_VALID_P (REGNO (dest)))
+	{
+	  int dest_q = REG_QTY (REGNO (dest));
+	  struct qty_table_elem *dest_ent = &qty_table[dest_q];
+
+	  if (dest_ent->mode == GET_MODE (dest)
+	      && dest_ent->first_reg != REGNO (dest)
+	      && GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
+	      /* Don't do this if the original insn had a hard reg as
+		 SET_SRC or SET_DEST.  */
+	      && (GET_CODE (sets[i].src) != REG
+		  || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
+	      && (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
+	    /* We can't call canon_reg here because it won't do anything if
+	       SRC is a hard register.  */
+	    {
+	      int src_q = REG_QTY (REGNO (src));
+	      struct qty_table_elem *src_ent = &qty_table[src_q];
+	      int first = src_ent->first_reg;
+	      rtx new_src
+		= (first >= FIRST_PSEUDO_REGISTER
+		   ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
+
+	      /* We must use validate-change even for this, because this
+		 might be a special no-op instruction, suitable only to
+		 tag notes onto.  */
+	      if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
+		{
+		  src = new_src;
+		  /* If we had a constant that is cheaper than what we are now
+		     setting SRC to, use that constant.  We ignored it when we
+		     thought we could make this into a no-op.  */
+		  if (src_const && COST (src_const) < COST (src)
+		      && validate_change (insn, &SET_SRC (sets[i].rtl), src_const,
+					  0))
+		    src = src_const;
+		}
 	    }
 	}
 
@@ -5284,22 +5372,27 @@ cse_insn (insn, libcall_insn)
 	     Rather than track each register individually, we just see if
 	     the last set for this quantity was for this register.  */
 
-	  if (REGNO_QTY_VALID_P (REGNO (dest))
-	      && qty_const[REG_QTY (REGNO (dest))] == const0_rtx)
+	  if (REGNO_QTY_VALID_P (REGNO (dest)))
 	    {
-	      /* See if we previously had a REG_WAS_0 note.  */
-	      rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
-	      rtx const_insn = qty_const_insn[REG_QTY (REGNO (dest))];
+	      int dest_q = REG_QTY (REGNO (dest));
+	      struct qty_table_elem *dest_ent = &qty_table[dest_q];
 
-	      if ((tem = single_set (const_insn)) != 0
-		  && rtx_equal_p (SET_DEST (tem), dest))
+	      if (dest_ent->const_rtx == const0_rtx)
 		{
-		  if (note)
-		    XEXP (note, 0) = const_insn;
-		  else
-		    REG_NOTES (insn)
-		      = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
-					   REG_NOTES (insn));
+		  /* See if we previously had a REG_WAS_0 note.  */
+		  rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
+		  rtx const_insn = dest_ent->const_insn;
+
+		  if ((tem = single_set (const_insn)) != 0
+		      && rtx_equal_p (SET_DEST (tem), dest))
+		    {
+		      if (note)
+			XEXP (note, 0) = const_insn;
+		      else
+			REG_NOTES (insn)
+			  = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
+					       REG_NOTES (insn));
+		    }
 		}
 	    }
 	}
@@ -5828,50 +5921,54 @@ cse_insn (insn, libcall_insn)
       && NEXT_INSN (PREV_INSN (insn)) == insn
       && GET_CODE (SET_SRC (sets[0].rtl)) == REG
       && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER
-      && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl)))
-      && (qty_first_reg[REG_QTY (REGNO (SET_SRC (sets[0].rtl)))]
-	  == REGNO (SET_DEST (sets[0].rtl)))
-      && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
-    {
-      rtx prev = PREV_INSN (insn);
-      while (prev && GET_CODE (prev) == NOTE)
-	prev = PREV_INSN (prev);
-
-      if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET
-	  && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
-	{
-	  rtx dest = SET_DEST (sets[0].rtl);
-	  rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
-
-	  validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
-	  validate_change (insn, & SET_DEST (sets[0].rtl),
-			   SET_SRC (sets[0].rtl), 1);
-	  validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1);
-	  apply_change_group ();
+      && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl))))
+    {
+      int src_q = REG_QTY (REGNO (SET_SRC (sets[0].rtl)));
+      struct qty_table_elem *src_ent = &qty_table[src_q];
+
+      if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
+	  && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+	{
+	  rtx prev = PREV_INSN (insn);
+	  while (prev && GET_CODE (prev) == NOTE)
+	    prev = PREV_INSN (prev);
 
-	  /* If REG1 was equivalent to a constant, REG0 is not.  */
-	  if (note)
-	    PUT_REG_NOTE_KIND (note, REG_EQUAL);
-
-	  /* If there was a REG_WAS_0 note on PREV, remove it.  Move
-	     any REG_WAS_0 note on INSN to PREV.  */
-	  note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
-	  if (note)
-	    remove_note (prev, note);
-
-	  note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
-	  if (note)
-	    {
-	      remove_note (insn, note);
-	      XEXP (note, 1) = REG_NOTES (prev);
-	      REG_NOTES (prev) = note;
-	    }
-
-	  /* If INSN has a REG_EQUAL note, and this note mentions REG0,
-	     then we must delete it, because the value in REG0 has changed.  */
-	  note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-	  if (note && reg_mentioned_p (dest, XEXP (note, 0)))
-	    remove_note (insn, note);
+	  if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET
+	      && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
+	    {
+	      rtx dest = SET_DEST (sets[0].rtl);
+	      rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
+
+	      validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
+	      validate_change (insn, & SET_DEST (sets[0].rtl),
+			       SET_SRC (sets[0].rtl), 1);
+	      validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1);
+	      apply_change_group ();
+
+	      /* If REG1 was equivalent to a constant, REG0 is not.  */
+	      if (note)
+		PUT_REG_NOTE_KIND (note, REG_EQUAL);
+
+	      /* If there was a REG_WAS_0 note on PREV, remove it.  Move
+		 any REG_WAS_0 note on INSN to PREV.  */
+	      note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
+	      if (note)
+		remove_note (prev, note);
+
+	      note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
+	      if (note)
+		{
+		  remove_note (insn, note);
+		  XEXP (note, 1) = REG_NOTES (prev);
+		  REG_NOTES (prev) = note;
+		}
+
+	      /* If INSN has a REG_EQUAL note, and this note mentions REG0,
+		 then we must delete it, because the value in REG0 has changed.  */
+	      note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+	      if (note && reg_mentioned_p (dest, XEXP (note, 0)))
+		remove_note (insn, note);
+	    }
 	}
     }
 
@@ -6049,14 +6146,18 @@ cse_process_notes (x, object)
       i = REG_QTY (REGNO (x));
 
       /* Return a constant or a constant register.  */
-      if (REGNO_QTY_VALID_P (REGNO (x))
-	  && qty_const[i] != 0
-	  && (CONSTANT_P (qty_const[i])
-	      || GET_CODE (qty_const[i]) == REG))
+      if (REGNO_QTY_VALID_P (REGNO (x)))
 	{
-	  rtx new = gen_lowpart_if_possible (GET_MODE (x), qty_const[i]);
-	  if (new)
-	    return new;
+	  struct qty_table_elem *ent = &qty_table[i];
+
+	  if (ent->const_rtx != NULL_RTX
+	      && (CONSTANT_P (ent->const_rtx)
+		  || GET_CODE (ent->const_rtx) == REG))
+	    {
+	      rtx new = gen_lowpart_if_possible (GET_MODE (x), ent->const_rtx);
+	      if (new)
+		return new;
+	    }
 	}
 
       /* Otherwise, canonicalize this register.  */
@@ -6615,8 +6716,8 @@ cse_main (f, nregs, after_loop, file)
 
   max_insn_uid = get_max_uid ();
 
-  reg_next_eqv = (int *) xmalloc (nregs * sizeof (int));
-  reg_prev_eqv = (int *) xmalloc (nregs * sizeof (int));
+  reg_eqv_table = (struct reg_eqv_elem *)
+    xmalloc(nregs * sizeof(struct reg_eqv_elem));
 
 #ifdef LOAD_EXTEND_OP
 
@@ -6753,17 +6854,13 @@ cse_main (f, nregs, after_loop, file)
   if (ggc_p)
     ggc_pop_context ();
 
-  /* Tell refers_to_mem_p that qty_const info is not available.  */
-  qty_const = 0;
-
   if (max_elements_made < n_elements_made)
     max_elements_made = n_elements_made;
 
   /* Clean up.  */
   end_alias_analysis ();
   free (uid_cuid);
-  free (reg_next_eqv);
-  free (reg_prev_eqv);
+  free (reg_eqv_table);
 
   return cse_jumps_altered || recorded_label_ref;
 }
@@ -6787,28 +6884,12 @@ cse_basic_block (from, to, next_branch, 
   rtx libcall_insn = NULL_RTX;
   int num_insns = 0;
 
-  /* Each of these arrays is undefined before max_reg, so only allocate
-     the space actually needed and adjust the start below.  */
+  /* This array is undefined before max_reg, so only allocate
+     the space actually needed and adjust the start.  */
 
-  qty_first_reg = (int *) xmalloc ((max_qty - max_reg) * sizeof (int));
-  qty_last_reg = (int *) xmalloc ((max_qty - max_reg) * sizeof (int));
-  qty_mode = (enum machine_mode *) xmalloc ((max_qty - max_reg)
-					   * sizeof (enum machine_mode));
-  qty_const = (rtx *) xmalloc ((max_qty - max_reg) * sizeof (rtx));
-  qty_const_insn = (rtx *) xmalloc ((max_qty - max_reg) * sizeof (rtx));
-  qty_comparison_code
-    = (enum rtx_code *) xmalloc ((max_qty - max_reg) * sizeof (enum rtx_code));
-  qty_comparison_qty = (int *) xmalloc ((max_qty - max_reg) * sizeof (int));
-  qty_comparison_const = (rtx *) xmalloc ((max_qty - max_reg) * sizeof (rtx));
-
-  qty_first_reg -= max_reg;
-  qty_last_reg -= max_reg;
-  qty_mode -= max_reg;
-  qty_const -= max_reg;
-  qty_const_insn -= max_reg;
-  qty_comparison_code -= max_reg;
-  qty_comparison_qty -= max_reg;
-  qty_comparison_const -= max_reg;
+  qty_table = (struct qty_table_elem *) xmalloc ((max_qty - max_reg)
+						 * sizeof(struct qty_table_elem));
+  qty_table -= max_reg;
 
   new_basic_block ();
 
@@ -6976,14 +7057,7 @@ cse_basic_block (from, to, next_branch, 
       && LABEL_NUSES (JUMP_LABEL (PREV_INSN (to))) == 1)
     cse_around_loop (JUMP_LABEL (PREV_INSN (to)));
 
-  free (qty_first_reg + max_reg);
-  free (qty_last_reg + max_reg);
-  free (qty_mode + max_reg);
-  free (qty_const + max_reg);
-  free (qty_const_insn + max_reg);
-  free (qty_comparison_code + max_reg);
-  free (qty_comparison_qty + max_reg);
-  free (qty_comparison_const + max_reg);
+  free (qty_table + max_reg);
 
   return to ? NEXT_INSN (to) : 0;
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]