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]
Other format: [Raw text]

[PATCH] Implement bitfield++ using XOR


The following patch improves the code we generate for incrementing
and decrementing bitfields.

Consider the function below, originally provided by Stan Cox.

struct {
   unsigned int bit0:1;
   unsigned int ubyte:31;
} sdata;

void foo()
{
  sdata.bit0++;
}


On IA-32 with -O2 -fomit-frame-pointer, mainline CVS currently generates:

foo:    movzbl  sdata, %edx
        movl    sdata, %eax
        andl    $1, %edx
        xorl    $1, %edx
        andl    $-2, %eax
        orl     %edx, %eax
        movl    %eax, sdata
        ret

with the patch below we now generate the much improved:

foo:	xorl	$1, sdata
	ret


The following patch has been tested on i686-pc-linux-gnu, all languages
except treelang, and powerpc-ibm-aix5.2.0.0, all languages except Java,
Ada and treelang, with full bootstraps and top-level "make -k check",
both with no new failures.

Ok for mainline?



2004-05-02  Roger Sayle  <roger@eyesopen.com>

	* expr.c (expand_increment): Optimize increment and decrement of
	single bit fields using bit-wise XOR.

	* gcc.c-torture/execute/bitfld-3.c: New test case.


Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.640
diff -c -3 -p -r1.640 expr.c
*** expr.c	30 Apr 2004 12:09:28 -0000	1.640
--- expr.c	1 May 2004 19:31:58 -0000
*************** expand_increment (tree exp, int post, in
*** 9144,9149 ****
--- 9144,9235 ----
        || TREE_CODE (incremented) == PREDECREMENT_EXPR)
      incremented = save_expr (incremented);

+   /* Optimize increment of a bitfield by a constant.  */
+   if (! post
+       && TREE_CODE (incremented) == COMPONENT_REF
+       && DECL_BIT_FIELD (TREE_OPERAND (incremented, 1))
+       && host_integerp (TREE_OPERAND (exp, 1), 1)
+       && ! TYPE_TRAP_SIGNED (TREE_TYPE (exp)))
+     {
+       HOST_WIDE_INT bitsize, bitpos;
+       int unsignedp, volatilep = 0;
+       enum machine_mode imode;
+       tree offset;
+
+       tree inner = get_inner_reference (incremented, &bitsize, &bitpos,
+ 					&offset, &imode, &unsignedp,
+ 					&volatilep);
+
+       /* Check for simple non-volatile fixed-width bit field references.  */
+       if (inner
+ 	  && offset == 0
+ 	  && imode == VOIDmode
+ 	  && !volatilep
+ 	  && TREE_CODE (inner) == VAR_DECL
+ 	  && SCALAR_INT_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+ 	  && GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (inner)))
+ 	     <= 2 * HOST_BITS_PER_WIDE_INT
+ 	  /* The transformations below can be generalized to any bitsize
+ 	     between 1 and HOST_BITS_PER_WIDE_INT (for suitable constants)
+ 	     but we currently only handle single bit fields.  */
+ 	  && bitsize == 1)
+ 	{
+ 	  unsigned HOST_WIDE_INT lo;
+ 	  HOST_WIDE_INT hi;
+ 	  tree temp, type;
+
+ 	  HOST_WIDE_INT delta = TREE_INT_CST_LOW (TREE_OPERAND (exp, 1));
+ 	  if (TREE_CODE (exp) == POSTDECREMENT_EXPR
+ 	      || TREE_CODE (exp) == PREDECREMENT_EXPR)
+ 	    delta = -delta;
+
+ 	  /* Mask the increment to the size of the bit-field.  */
+ 	  delta &= 1;
+
+ 	  /* If the increment doesn't affect the bitfield, do nothing.  */
+ 	  if (delta == 0)
+ 	    {
+ 	      if (ignore)
+ 		return const0_rtx;
+ 	      return expand_expr (incremented, NULL_RTX, VOIDmode, 0);
+ 	    }
+
+ 	  /* An addition of a constant that has only the most significant
+ 	     bit set is equivalent to a bit-wise XOR of that constant.
+ 	     The XOR can be performed directly on the bitfield, rather than
+ 	     extracting it, performing the addition then storing it back.  */
+
+ 	  imode = TYPE_MODE (TREE_TYPE (inner));
+ 	  if (BYTES_BIG_ENDIAN)
+ 	    bitpos = GET_MODE_BITSIZE (imode) - 1 - bitpos;
+
+ 	  if (bitpos >= HOST_BITS_PER_WIDE_INT)
+ 	    {
+ 	      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ 	      lo = 0;
+ 	    }
+ 	  else
+ 	    {
+ 	      hi = 0;
+ 	      lo = (unsigned HOST_WIDE_INT) 1 << bitpos;
+ 	    }
+
+ 	  type = lang_hooks.types.type_for_mode (imode, 1);
+ 	  temp = build_int_2 (lo, hi);
+ 	  TREE_TYPE (temp) = type;
+
+ 	  temp = fold (build2 (BIT_XOR_EXPR, type,
+ 			       fold (build1 (NOP_EXPR, type, inner)),
+ 			       temp));
+ 	  temp = fold (build1 (NOP_EXPR, TREE_TYPE (inner), temp));
+ 	  expand_assignment (inner, temp, 0);
+
+ 	  if (ignore)
+ 	    return const0_rtx;
+ 	  return expand_expr (incremented, NULL_RTX, VOIDmode, 0);
+ 	}
+     }
+
    /* Compute the operands as RTX.
       Note whether OP0 is the actual lvalue or a copy of it:
       I believe it is a copy iff it is a register or subreg


extern void abort (void);

struct {
   unsigned int bit0:1;
   unsigned int bit1:1;
   unsigned int bit2:1;
   unsigned int bit3:1;
   unsigned int bit4:1;
   unsigned int bit5:1;
   unsigned int bit6:1;
   unsigned int bit7:1;
   unsigned int bit8:1;
   unsigned int bit9:1;
   unsigned int bit10:1;
   unsigned int bit11:1;
   unsigned int bit12:1;
   unsigned int bit13:1;
   unsigned int bit14:1;
   unsigned int bit15:1;
} sdata;

#define TEST(N) sdata.bit##N = 0;	\
		sdata.bit##N++;		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		sdata.bit##N++;		\
		if (sdata.bit##N != 0)  \
		  abort ();		\
		sdata.bit##N--;		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		sdata.bit##N--;		\
		if (sdata.bit##N != 0)	\
		  abort ();		\
		++sdata.bit##N;		\
		if (sdata.bit##N != 1)  \
		  abort ();		\
		++sdata.bit##N;		\
		if (sdata.bit##N != 0)  \
		  abort ();		\
		--sdata.bit##N;		\
		if (sdata.bit##N != 1)  \
		  abort ();		\
		--sdata.bit##N;		\
		if (sdata.bit##N != 0)  \
		  abort ();		\
		if (sdata.bit##N++ != 0)\
		  abort ();		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		if (sdata.bit##N++ != 1)\
		  abort ();		\
		if (sdata.bit##N != 0)	\
		  abort ();		\
		if (sdata.bit##N-- != 0)\
		  abort ();		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		if (sdata.bit##N-- != 1)\
		  abort ();		\
		if (sdata.bit##N != 0)	\
		  abort ();		\
		if (++sdata.bit##N != 1)\
		  abort ();		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		if (++sdata.bit##N != 0)\
		  abort ();		\
		if (sdata.bit##N != 0)	\
		  abort ();		\
		if (--sdata.bit##N != 1)\
		  abort ();		\
		if (sdata.bit##N != 1)	\
		  abort ();		\
		if (--sdata.bit##N != 0)\
		  abort ();		\
		if (sdata.bit##N != 0)	\
		  abort ();



int main()
{
  TEST (0);
  TEST (7);
  TEST (8);
  TEST (15);
  return 0;
}



Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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