[Committed] 4.1: pr14261 ifcvt and store_bit_field patches

Andreas Krebbel krebbel1@de.ibm.com
Mon May 15 14:51:00 GMT 2006


Hello Roger,

I've committed both patches after retesting. The patches
fix the related testcases and pass bootstrap and regtesting
on i686, s390 and s390x.

http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00697.html
http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00951.html

For the list: I've got an offlist approval for committing
this to gcc 4.1 from Roger.

Bye,

-Andreas-

2006-05-15  Andreas Krebbel  <krebbel1@de.ibm.com>

	PR rtl-optimization/14261
	* ifcvt.c (noce_emit_move_insn): Call store_bit_field if the resulting
	move would be an INSV insn.
	(noce_process_if_block): Don't optimize if the destination is a 
	ZERO_EXTRACT which can't be handled by noce_emit_move_insn.

2006-05-15  Andreas Krebbel  <krebbel1@de.ibm.com>

	* expmed.c (store_bit_field): Handle paradoxical subregs on big endian
	machines.

2006-05-15  Andreas Krebbel  <krebbel1@de.ibm.com>

	* gcc.dg/20060515-1.c: New testcase.

2006-05-15  Andreas Krebbel  <krebbel1@de.ibm.com>

	PR rtl-optimization/14261
	* gcc.c-torture/compile/20060515-1.c: Likewise.


Index: gcc/ifcvt.c
===================================================================
*** gcc/ifcvt.c.orig	2006-04-07 12:34:23.000000000 +0200
--- gcc/ifcvt.c	2006-04-18 13:44:49.000000000 +0200
*************** noce_emit_move_insn (rtx x, rtx y)
*** 702,748 ****
        end_sequence();
  
        if (recog_memoized (insn) <= 0)
! 	switch (GET_RTX_CLASS (GET_CODE (y)))
! 	  {
! 	  case RTX_UNARY:
! 	    ot = code_to_optab[GET_CODE (y)];
! 	    if (ot)
! 	      {
! 		start_sequence ();
! 		target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
! 		if (target != NULL_RTX)
! 		  {
! 		    if (target != x)
! 		      emit_move_insn (x, target);
! 		    seq = get_insns ();
! 		  }
! 		end_sequence ();
! 	      }
! 	    break;
! 
! 	  case RTX_BIN_ARITH:
! 	  case RTX_COMM_ARITH:
! 	    ot = code_to_optab[GET_CODE (y)];
! 	    if (ot)
! 	      {
! 		start_sequence ();
! 		target = expand_binop (GET_MODE (y), ot,
! 				       XEXP (y, 0), XEXP (y, 1),
! 				       x, 0, OPTAB_DIRECT);
! 		if (target != NULL_RTX)
! 		  {
! 		    if (target != x)
! 		      emit_move_insn (x, target);
! 		    seq = get_insns ();
! 		  }
! 		end_sequence ();
! 	      }
! 	    break;
  
! 	  default:
! 	    break;
! 	  }
  
        emit_insn (seq);
        return;
      }
--- 702,777 ----
        end_sequence();
  
        if (recog_memoized (insn) <= 0)
! 	{
! 	  if (GET_CODE (x) == ZERO_EXTRACT)
! 	    {
! 	      rtx op = XEXP (x, 0);
! 	      unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
! 	      unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
! 
! 	      /* store_bit_field expects START to be relative to 
! 		 BYTES_BIG_ENDIAN and adjusts this value for machines with 
! 		 BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN.  In order to be able to 
! 		 invoke store_bit_field again it is necessary to have the START
! 		 value from the first call.  */
! 	      if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
! 		{
! 		  if (MEM_P (op))
! 		    start = BITS_PER_UNIT - start - size;
! 		  else
! 		    {
! 		      gcc_assert (REG_P (op));
! 		      start = BITS_PER_WORD - start - size;
! 		    }
! 		}
  
! 	      gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
! 	      store_bit_field (op, size, start, GET_MODE (x), y);
! 	      return;
! 	    }
  
+ 	  switch (GET_RTX_CLASS (GET_CODE (y)))
+ 	    {
+ 	    case RTX_UNARY:
+ 	      ot = code_to_optab[GET_CODE (y)];
+ 	      if (ot)
+ 		{
+ 		  start_sequence ();
+ 		  target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
+ 		  if (target != NULL_RTX)
+ 		    {
+ 		      if (target != x)
+ 			emit_move_insn (x, target);
+ 		      seq = get_insns ();
+ 		    }
+ 		  end_sequence ();
+ 		}
+ 	      break;
+ 	      
+ 	    case RTX_BIN_ARITH:
+ 	    case RTX_COMM_ARITH:
+ 	      ot = code_to_optab[GET_CODE (y)];
+ 	      if (ot)
+ 		{
+ 		  start_sequence ();
+ 		  target = expand_binop (GET_MODE (y), ot,
+ 					 XEXP (y, 0), XEXP (y, 1),
+ 					 x, 0, OPTAB_DIRECT);
+ 		  if (target != NULL_RTX)
+ 		    {
+ 		      if (target != x)
+ 			  emit_move_insn (x, target);
+ 		      seq = get_insns ();
+ 		    }
+ 		  end_sequence ();
+ 		}
+ 	      break;
+ 	      
+ 	    default:
+ 	      break;
+ 	    }
+ 	}
+       
        emit_insn (seq);
        return;
      }
*************** noce_process_if_block (struct ce_if_bloc
*** 2231,2236 ****
--- 2260,2271 ----
      {
        if (no_new_pseudos || GET_MODE (x) == BLKmode)
  	return FALSE;
+ 
+       if (GET_MODE (x) == ZERO_EXTRACT 
+ 	  && (GET_CODE (XEXP (x, 1)) != CONST_INT 
+ 	      || GET_CODE (XEXP (x, 2)) != CONST_INT))
+ 	return FALSE;
+ 	  
        x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
  				 ? XEXP (x, 0) : x));
      }
Index: gcc/testsuite/gcc.c-torture/compile/20060515-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.c-torture/compile/20060515-1.c	2006-04-18 13:33:10.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ /* This failed because if conversion didn't handle insv patterns properly.  */
+ 
+ union y
+ {
+   int a;
+   unsigned short b;
+ };
+ 
+ extern void bar (unsigned short u, union y v);
+ 
+ void
+ foo (int check)
+ {
+   union y x;
+ 
+   if (check != 0)
+     x.b = 1;
+   else
+     x.b = 2;
+   bar (x.b, x);
+ }


Index: gcc/expmed.c
===================================================================
*** gcc/expmed.c.orig	2006-05-15 10:33:32.000000000 +0200
--- gcc/expmed.c	2006-05-15 12:57:43.000000000 +0200
*************** store_bit_field (rtx str_rtx, unsigned H
*** 353,359 ****
  	 meaningful at a much higher level; when structures are copied
  	 between memory and regs, the higher-numbered regs
  	 always get higher addresses.  */
!       bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
        op0 = SUBREG_REG (op0);
      }
  
--- 353,377 ----
  	 meaningful at a much higher level; when structures are copied
  	 between memory and regs, the higher-numbered regs
  	 always get higher addresses.  */
!       int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
!       int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
!       
!       byte_offset = 0;
! 
!       /* Paradoxical subregs need special handling on big endian machines.  */
!       if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size)
! 	{
! 	  int difference = inner_mode_size - outer_mode_size;
! 
! 	  if (WORDS_BIG_ENDIAN)
! 	    byte_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
! 	  if (BYTES_BIG_ENDIAN)
! 	    byte_offset += difference % UNITS_PER_WORD;
! 	}
!       else
! 	byte_offset = SUBREG_BYTE (op0);
! 
!       bitnum += byte_offset * BITS_PER_UNIT;
        op0 = SUBREG_REG (op0);
      }
  
Index: gcc/testsuite/gcc.dg/20060515-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/20060515-1.c	2006-05-15 12:57:43.000000000 +0200
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-do run } */
+ /* { dg-options "-O1" } */
+ 
+ /* This failed because if conversion didn't handle insv patterns properly.  */
+ 
+ void abort (void);
+ 
+ union y
+ {
+   int a;
+   unsigned short b;
+ };
+ 
+ void __attribute__ ((noinline))
+ bar (unsigned short u, union y v)
+ {
+   if (u != 1)
+     abort ();
+ }
+ 
+ void __attribute__ ((noinline))
+ foo (int check)
+ {
+   union y x;
+ 
+   if (check != 0)
+     x.b = 1;
+   else
+     x.b = 2;
+   bar (x.b, x);
+ }
+ 
+ int
+ main ()
+ {
+   foo (1);
+   return 0;
+ }



More information about the Gcc-patches mailing list