solaris bootstrap failures

Jeffrey A Law
Wed Feb 24 05:11:00 GMT 1999

Loop was not the culprit.  loop helped trigger the problem, but that was
only because it rearranged stuff on the stack a little bit.

The real bug was a fairly obscure problem with the address operand handling in

Consider an insn with a single alternative which specified 'p'.

Let's assume that operand is a pseudo reg in the rtl and that a raw pseudo
is a valid address operand.

In that case the big case statement in record_reg_class would set
"allows_addr".  But classes for that operand would still contain NO_REGS.

We'd get out of the case statement and hit this code:

          /* How we account for this operand now depends on whether it is  a
             pseudo register or not.  If it is, we first check if any
             register classes are valid.  If not, we ignore this alternative,
             since we want to assume that all pseudos get allocated for
             register preferencing.  If some register class is valid, compute
             the costs of moving the pseudo into that class.  */

          if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
              if (classes[i] == NO_REGS)
                  if (! allows_addr)
                    alt_fail = 1;
	     /* Update this_op_costs... */

	 [ blah blah blah ]

      if (alt_fail)

      /* Finally, update the costs with the information we've calculated
         about this alternative.  */

      for (i = 0; i < n_ops; i++)
        if (GET_CODE (ops[i]) == REG
            && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
            struct costs *pp = &op_costs[i], *qq = &this_op_costs[i];
            int scale = 1 + (recog_op_type[i] == OP_INOUT);

            pp->mem_cost = MIN (pp->mem_cost,
                                (qq->mem_cost + alt_cost) * scale);

            for (class = 0; class < N_REG_CLASSES; class++)
              pp->cost[class] = MIN (pp->cost[class],
                                     (qq->cost[class] + alt_cost) * scale);

alt_fail will be zero, so we do not continue the outer loop (not shown).  So
we fall into the for loop (shown above), which reads from this_op_costs, which
was never initialized.  This leads to the comparison failure.

I think the right fix involves two changes.

First, for a 'p' constraint, set class[i] to:

                  reg_class_subunion[(int) classes[i]] [BASE_REG_CLASS]

That way we'll try to find an appropriate base register to hold the address.

Then, remove the (! allows_addr) check in the code above.

I'm bootstrapping a compiler with this fix:

	* regclass.c (record_reg_classes, case 'p'): Set classes appropriately.
	An alternative always fails if it needs a pseudo and now suitable
	register class can be found.

Index: regclass.c
RCS file: /egcs/carton/cvsfiles/egcs/gcc/regclass.c,v
retrieving revision 1.52
diff -c -3 -p -r1.52 regclass.c
*** regclass.c	1999/02/18 19:49:19	1.52
--- regclass.c	1999/02/24 13:06:16
*************** record_reg_classes (n_alts, n_ops, ops, 
*** 1268,1273 ****
--- 1268,1279 ----
  	      case 'p':
  		allows_addr = 1;
  		win = address_operand (op, GET_MODE (op));
+ 		/* We know this operand is an address, so we want it to be
+ 		   allocated to a register that can be the base of an
+ 		   address, ie BASE_REG_CLASS.  */
+ 		classes[i]
+ 		  = reg_class_subunion[(int) classes[i]]
+ 		    [(int) BASE_REG_CLASS];
  	      case 'm':  case 'o':  case 'V':
*************** record_reg_classes (n_alts, n_ops, ops, 
*** 1399,1405 ****
  	      if (classes[i] == NO_REGS)
! 		  if (! allows_addr)
  		    alt_fail = 1;
--- 1405,1416 ----
  	      if (classes[i] == NO_REGS)
! 		    /* We must always fail if the operand is a REG, but
! 		       we did not find a suitable class.
! 		       Otherwise we may perform an uninitialized read
! 		       from this_op_costs after the `continue' statement
! 		       below.  */
  		    alt_fail = 1;

is a va

More information about the Gcc-patches mailing list