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]

MIPS/regclass patch: fix handling of se_register_operands



Testcase: gcc.c-torture/execute/200010518-2.c
Target: mips64-elf -mips3 -EB

In 64-bit mode, the mips backend often allows instructions to have operands
of the form (sign_extend:DI X), where X is an SI register_operand.
SECONDARY_RELOAD_CLASS handles such operands with the code:

-------------------------------------------------------------------------
  if (GET_CODE (x) == SIGN_EXTEND)
    {
      int off = 0;

      x = XEXP (x, 0);

      /* We may be called with reg_renumber NULL from regclass.
	 ??? This is probably a bug.  */
      if (reg_renumber)
	regno = true_regnum (x);
      else
	{
	  while (GET_CODE (x) == SUBREG)
	    {
	      off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
					  GET_MODE (SUBREG_REG (x)),
					  SUBREG_BYTE (x),
					  GET_MODE (x));
	      x = SUBREG_REG (x);
	    }

	  if (GET_CODE (x) == REG)
	    regno = REGNO (x) + off;
	}
    }
-------------------------------------------------------------------------

This code causes an ICE on execute/20010518-2.c in big endian mode.  The
function is being called from regclass with X set to a sign_extend of a
subreg of a pseudo.  Seeing the subreg, the code calls subreg_regno_offset,
which applies only to hard registers.

sign_extend operands are allowed because an SI value in a 64-bit register
will already be sign extended.  So in this case regclass should really be
looking at the argument to the sign_extend when deciding what class of
register to use, much in the same way that it looks at the contents of a
subreg rather than the subreg itself.

Rather than make regclass treat sign_extend as a special case, is it OK to
generalise the rule to: given an operand (UNOP X) when X also matches the
operand's predicate, regclass should base the choice of register class on X?
The patch below does that, and removes the handling of regclass calls quoted
above.  The new version of SECONDARY_RELOAD_CLASS will abort when given a
sign_extend of a pseudo.

The patch was tested on i686-pc-linux-gnu-x-mips64-elf with -mips3 -EB and
-mips3 -EL.  Fixes the test case, introduced no c-torture regressions,
bootstraps on i686-pc-linux-gnu (--enable-languages=c,c++,f77).

OK to install?



2001-06-26  Richard Sandiford  <rsandifo@redhat.com>

	* regclass.c (record_operand_costs): If an operand is a unary
	operation, and the argument to the unary operation is also
	valid, consider the argument when deciding on a register class.
	* config/mips/mips.md (mips_secondary_reload_class): Assume that
	regclass will not call this function with a sign_extend operand.

Index: regclass.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regclass.c,v
retrieving revision 1.121
diff -c -p -d -r1.121 regclass.c
*** regclass.c	2001/06/22 23:27:47	1.121
--- regclass.c	2001/06/26 20:42:13
*************** record_operand_costs (insn, op_costs, re
*** 894,899 ****
--- 894,900 ----
       struct costs *op_costs;
       struct reg_pref *reg_pref;
  {
+   const struct insn_data *data = &insn_data[(int) INSN_CODE (insn)];
    const char *constraints[MAX_RECOG_OPERANDS];
    enum machine_mode modes[MAX_RECOG_OPERANDS];
    int i;
*************** record_operand_costs (insn, op_costs, re
*** 912,936 ****
  	     
    for (i = 0; i < recog_data.n_operands; i++)
      {
        op_costs[i] = init_cost;
  
!       if (GET_CODE (recog_data.operand[i]) == SUBREG)
  	{
! 	  rtx inner = SUBREG_REG (recog_data.operand[i]);
  #ifdef CLASS_CANNOT_CHANGE_MODE
! 	  if (GET_CODE (inner) == REG
! 	      && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner)))
! 	    SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner));
  #endif
- 	  recog_data.operand[i] = inner;
  	}
  
!       if (GET_CODE (recog_data.operand[i]) == MEM)
! 	record_address_regs (XEXP (recog_data.operand[i], 0),
! 			     BASE_REG_CLASS, frequency * 2);
        else if (constraints[i][0] == 'p')
! 	record_address_regs (recog_data.operand[i],
! 			     BASE_REG_CLASS, frequency * 2);
      }
  
    /* Check for commutative in a separate loop so everything will
--- 913,950 ----
  	     
    for (i = 0; i < recog_data.n_operands; i++)
      {
+       rtx op;
+ 
        op_costs[i] = init_cost;
+       op = recog_data.operand[i];
  
!       /* If, for some unary operation UNOP, an operand UNOP(X) is equivalent
! 	 to an operand X, the operand's predicate may allow both UNOP(X) and
! 	 X.  For example, the MIPS back-end has an se_register_operand
! 	 predicate that allows register and sign-extended register operands.
! 	 The regclass pass is interested in the inner part of such
! 	 operands.  */
!       while (GET_RTX_CLASS (GET_CODE (op)) == '1'
! 	     && (data->operand[i].predicate) (XEXP (op, 0),
! 					      GET_MODE (XEXP (op, 0))))
! 	op = XEXP (op, 0);
! 
!       if (GET_CODE (op) == SUBREG)
  	{
! 	  op = SUBREG_REG (op);
  #ifdef CLASS_CANNOT_CHANGE_MODE
! 	  if (GET_CODE (op) == REG
! 	      && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (op)))
! 	    SET_REGNO_REG_SET (reg_changes_mode, REGNO (op));
  #endif
  	}
  
!       recog_data.operand[i] = op;
! 
!       if (GET_CODE (op) == MEM)
! 	record_address_regs (XEXP (op, 0), BASE_REG_CLASS, frequency * 2);
        else if (constraints[i][0] == 'p')
! 	record_address_regs (op, BASE_REG_CLASS, frequency * 2);
      }
  
    /* Check for commutative in a separate loop so everything will
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.117
diff -c -p -d -r1.117 mips.c
*** config/mips/mips.c	2001/05/31 19:39:30	1.117
--- config/mips/mips.c	2001/06/26 20:42:21
*************** mips_secondary_reload_class (class, mode
*** 7990,8021 ****
    int gp_reg_p;
  
    if (GET_CODE (x) == SIGN_EXTEND)
!     {
!       int off = 0;
! 
!       x = XEXP (x, 0);
! 
!       /* We may be called with reg_renumber NULL from regclass.
! 	 ??? This is probably a bug.  */
!       if (reg_renumber)
! 	regno = true_regnum (x);
!       else
! 	{
! 	  while (GET_CODE (x) == SUBREG)
! 	    {
! 	      off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
! 					  GET_MODE (SUBREG_REG (x)),
! 					  SUBREG_BYTE (x),
! 					  GET_MODE (x));
! 	      x = SUBREG_REG (x);
! 	    }
! 
! 	  if (GET_CODE (x) == REG)
! 	    regno = REGNO (x) + off;
! 	}
!     }
! 
!   else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
      regno = true_regnum (x);
  
    gp_reg_p = TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);
--- 7993,8000 ----
    int gp_reg_p;
  
    if (GET_CODE (x) == SIGN_EXTEND)
!     x = XEXP (x, 0);
!   if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
      regno = true_regnum (x);
  
    gp_reg_p = TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);


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