expand_field_assignment fix

Jan Hubicka jh@suse.cz
Tue Dec 12 05:22:00 GMT 2000


Oops, sorry for sending the patches to the gcc mailing list instead of to
patches!

Hi
expand_field_assignment is wrong when dealing with expressions like:
(zero_extract:SI (mem:QI (address) (const_int x) (reg y)))
The mode of MEM operand for ZERO_EXTRACT is documented to be always QImode:

     If LOC is in memory, its mode must be a single-byte integer mode.
     If LOC is in a register, the mode to use is specified by the
     operand of the `insv' or `extv' pattern (*note Standard Names::.)
     and is usually a full-word integer mode, which is the default if
     none is specified.

so we don't know what range the register REG may be in, but
expand_field_assignment always translates this into QImode shifts.  We are only
lucky, that the resulting sequence is so complex, that it never simplifies
properly, but I have followup patch for this.

The patch makes variable shifts to be refused and constant to be translated
into smallest suitable integer mode.

In future it would be nice to change ZERO_EXTRACT definition, to make mode on
memory limiting the range of possible possitions and using BLKmode on unlimited
range bitfield operations, but this is out of scope of this patch.

Bootstrapped and regtested on i386 with only unrelated failures in the
haifa scheduler probably related to Bernd's work.

Honza

Tue Dec 12 13:44:54 MET 2000  Jan Hubicka  <jh@suse.cz>

	* combine.c (expand_field_assignment): Refuse ZERO_EXTRACTs on MEMs
	with variable counts and choose proper mode for ZERO_EXTRACTs on MEMs
	with constant counts.

Index: egcs/gcc/combine.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/combine.c,v
retrieving revision 1.169
diff -c -3 -p -r1.169 combine.c
*** combine.c	2000/12/01 12:45:00	1.169
--- combine.c	2000/12/11 20:12:51
*************** expand_field_assignment (x)
*** 5786,5796 ****
  	  len = INTVAL (XEXP (SET_DEST (x), 1));
  	  pos = XEXP (SET_DEST (x), 2);
  
! 	  /* If the position is constant and spans the width of INNER,
! 	     surround INNER  with a USE to indicate this.  */
  	  if (GET_CODE (pos) == CONST_INT
  	      && INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
! 	    inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner);
  
  	  if (BITS_BIG_ENDIAN)
  	    {
--- 5786,5822 ----
  	  len = INTVAL (XEXP (SET_DEST (x), 1));
  	  pos = XEXP (SET_DEST (x), 2);
  
! 	  /* MEMs are always QImode, but may refer to arbitary large memory.
! 	     in case both POS and LEN and constants, we may determine mode
! 	     needed, otherwise we need to give up.
! 
! 	     ??? It would be nice if rules for mode on MEM operand changed,
! 	     so the mode was same as for register and using BLKmode for
! 	     arbitary large references.  */
! 	  if (GET_CODE (inner) == MEM)
! 	    {
! 	      HOST_WIDE_INT size;
! 	      enum machine_mode tmode;
! 	      if (GET_CODE (pos) != CONST_INT)
! 		break;
! 	      if (GET_MODE (inner) != QImode)
! 		abort();
! 	      /* ??? We may support adjusting memory here to get narrower
! 		 mode.  */
! 	      size = len + INTVAL (pos);
! 	      for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (QImode));
! 		   (tmode != VOIDmode
! 		    && GET_MODE_BITSIZE (tmode) < size);
! 		   tmode = GET_MODE_WIDER_MODE (tmode))
! 	      if (tmode == VOIDmode)
! 		break;
! 	      inner = gen_lowpart_for_combine (tmode, inner);
! 	    }
! 	  /* For non-memory operands we should never run out of the
! 	     operand.  */
  	  if (GET_CODE (pos) == CONST_INT
  	      && INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
! 	    abort();
  
  	  if (BITS_BIG_ENDIAN)
  	    {


More information about the Gcc-patches mailing list