diff mbox

Fix BIT_NOT_EXPR expansion with bitfields

Message ID alpine.LNX.2.00.1107181400010.810@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener July 18, 2011, 12:04 p.m. UTC
We currently fail to handle bitfield precision BIT_NOT_EXPRs properly
and miscompile the testcase below.  Fixed by properly truncating to
bitfield precision if required.  Do that by expanding the NOT to
a proper XOR instead of doing the truncation via a AND though.

Bootstrap and regtest pending on x86_64-unknown-linux-gnu.

Richard.

2011-07-18  Richard Guenther  <rguenther@suse.de>

	* expr.c (expand_expr_real_2): Properly truncate the BIT_NOT_EXPR
	expansion result to bitfield precision if required.

	* gcc.dg/torture/20110718-1.c: New testcase.
diff mbox

Patch

Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 176386)
+++ gcc/expr.c	(working copy)
@@ -8037,7 +8037,15 @@  expand_expr_real_2 (sepops ops, rtx targ
 			 VOIDmode, EXPAND_NORMAL);
       if (modifier == EXPAND_STACK_PARM)
 	target = 0;
-      temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
+      /* In case we have to reduce the result to bitfield precision
+	 expand this as XOR with a proper constant instead.  */
+      if (reduce_bit_field)
+	temp = expand_binop (mode, xor_optab, op0,
+			     immed_double_int_const
+			       (double_int_mask (TYPE_PRECISION (type)), mode),
+			     target, 1, OPTAB_LIB_WIDEN);
+      else
+	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
       return temp;
 
Index: gcc/testsuite/gcc.dg/torture/20110718-1.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/20110718-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/20110718-1.c	(revision 0)
@@ -0,0 +1,17 @@ 
+/* { dg-do run } */
+
+extern void abort (void);
+struct X { unsigned long i : 33; };
+unsigned long __attribute__((noinline))
+foo (struct X *p)
+{
+  return ~p->i;
+}
+int main()
+{
+  struct X x;
+  x.i = -1;
+  if (foo (&x) != 0)
+    abort ();
+  return 0;
+}