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]

Bit-field patch, resurrected


Here at last is the resurrected bit-field patch to give bit-fields in
C their proper types (integer types of the specified signedness and
width, as required by the C standard, rather than the declared types);
Neil's original patch was
<http://gcc.gnu.org/ml/gcc-patches/2002-01/msg02014.html> which had to
be reverted <http://gcc.gnu.org/ml/gcc-patches/2002-02/msg00039.html>
because of ABI and GDB testsuite problems it caused.  (Note that this
requirement on types of bit-fields is a difference between C and C++;
in C++ bit-fields have their declared types and just a narrow
representation, so an unsigned:3 bit-field promotes to int in C but to
unsigned in C++.  This was noted in passing in a long discussion on
bool bit-fields on the WG14 reflector in January; there was no clear
consensus from that discussion on the details of how bool bit-fields
should work (whether conversions to them should act like conversions
to bool or conversions to an ordinary integer type, etc.), but a clear
consensus on the meaning of bit-fields of other integer types, as was
confirmed in some C90 DRs.)

This is one more step towards correct C90(!) support (and so to C99,
which needs correct handling of features shared with C90 as well as
new language features).  (It's also one which has attracted frequent
bug reports; the PRs listed have many duplicates that have been closed
as such.)

The changes to expand_expr_real follow the approach I indicated in
<http://gcc.gnu.org/ml/gcc-patches/2003-12/msg00651.html>, as no
comments were received then.  The langhook is since other languages
seem to use types narrower than their modes in ways that trigger this
code undesirably; without the langhook, the Ada bootstrap failed and
there were many failures in the libjava testsuite.

This patch has been bootstrapped with no regressions, GCC and GDB
testsuites, on i686-pc-linux-gnu.  (The gcc.dg/compat testsuite
doesn't test bit-fields, so this is of limited assurance with regard
to ABI issues, but I hope the delay in giving bit-fields their proper
types until after layout will have avoided such problems this time,
and the ABI testcases added to show problems with Neil's original
patch do pass.)  OK to commit?

2004-03-16  Neil Booth  <neil@daikokuya.co.uk>
            Joseph S. Myers  <jsm@polyomino.org.uk>

	PR c/2511
	PR c/3325
	* c-decl.c (finish_struct): Ensure bit-fields are given the
	correct type.
	* c-common.c (c_common_signed_or_unsigned_type): Except for
	ENUMERAL_TYPEs, require the precision to match as well as the
	mode.
	* expr.c (reduce_to_bit_field_precision): New function.
	(expand_expr_real): Reduce expressions of bit-field type to proper
	precision.
	* langhooks.h (reduce_bit_field_operations): New hook.
	* langhooks-def.h (LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS):
	Define.
	* c-lang.c, objc/objc-lang.c
	(LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS): Define.
	* objc/objc-act.c (check_ivars): Convert types to bit-field types
	before checking.
	* tree.c (build_nonstandard_integer_type): New function.
	* tree.h (build_nonstandard_integer_type): New prototype.

testsuite:
2004-03-16  Joseph S. Myers  <jsm@polyomino.org.uk>

	* gcc.c-torture/execute/bitfld-1.x: Remove.
	* gcc.c-torture/execute/bitfld-3.c: New test.
	* gcc.dg/bitfld-2.c: Remove XFAILs.

diff -rupN GCC.orig/gcc/c-common.c GCC/gcc/c-common.c
--- GCC.orig/gcc/c-common.c	2004-03-04 17:19:37.000000000 +0000
+++ GCC/gcc/c-common.c	2004-03-06 23:41:51.000000000 +0000
@@ -1988,44 +1988,55 @@ c_common_signed_type (tree type)
 tree
 c_common_signed_or_unsigned_type (int unsignedp, tree type)
 {
+  bool mode_only_needed;
+
   if (! INTEGRAL_TYPE_P (type)
       || TREE_UNSIGNED (type) == unsignedp)
     return type;
 
-  /* Must check the mode of the types, not the precision.  Enumeral types
-     in C++ have precision set to match their range, but may use a wider
+  /* For ENUMERAL_TYPEs, must check the mode of the types, not the precision;
+     in C++ they have precision set to match their range, but may use a wider
      mode to match an ABI.  If we change modes, we may wind up with bad
-     conversions.  */
-
-  if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node))
+     conversions.  For INTEGER_TYPEs, must check the precision as well, so
+     as to yield correct results for bit-field types.  */
+  mode_only_needed = (TREE_CODE (type) == ENUMERAL_TYPE);
+
+#define TYPE_OK(node)							    \
+  (TYPE_MODE (type) == TYPE_MODE (node)					    \
+   && (mode_only_needed || TYPE_PRECISION (type) == TYPE_PRECISION (node)))
+  if (TYPE_OK (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (integer_type_node))
+  if (TYPE_OK (integer_type_node))
     return unsignedp ? unsigned_type_node : integer_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node))
+  if (TYPE_OK (short_integer_type_node))
     return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node))
+  if (TYPE_OK (long_integer_type_node))
     return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node))
+  if (TYPE_OK (long_long_integer_type_node))
     return (unsignedp ? long_long_unsigned_type_node
 	    : long_long_integer_type_node);
-  if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node))
+  if (TYPE_OK (widest_integer_literal_type_node))
     return (unsignedp ? widest_unsigned_literal_type_node
 	    : widest_integer_literal_type_node);
 
 #if HOST_BITS_PER_WIDE_INT >= 64
-  if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node))
+  if (TYPE_OK (intTI_type_node))
     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
 #endif
-  if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node))
+  if (TYPE_OK (intDI_type_node))
     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node))
+  if (TYPE_OK (intSI_type_node))
     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node))
+  if (TYPE_OK (intHI_type_node))
     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
-  if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node))
+  if (TYPE_OK (intQI_type_node))
     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+#undef TYPE_OK
 
-  return type;
+  if (mode_only_needed)
+    return type;
+  else
+    return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
 }
 
 /* The C version of the register_builtin_type langhook.  */
diff -rupN GCC.orig/gcc/c-decl.c GCC/gcc/c-decl.c
--- GCC.orig/gcc/c-decl.c	2004-03-04 17:19:37.000000000 +0000
+++ GCC/gcc/c-decl.c	2004-03-06 23:41:51.000000000 +0000
@@ -4944,9 +4944,11 @@ finish_struct (tree t, tree fieldlist, t
     }
 
   /* Install struct as DECL_CONTEXT of each field decl.
-     Also process specified field sizes,m which is found in the DECL_INITIAL.
-     Store 0 there, except for ": 0" fields (so we can find them
-     and delete them, below).  */
+     Also process specified field sizes, found in the DECL_INITIAL,
+     storing 0 there after the type has been changed to precision equal
+     to its width, rather than the precision of the specified standard
+     type.  (Correct layout requires the original type to have been preserved
+     until now.)  */
 
   saw_named_field = 0;
   for (x = fieldlist; x; x = TREE_CHAIN (x))
@@ -4990,8 +4992,6 @@ finish_struct (tree t, tree fieldlist, t
 	  SET_DECL_C_BIT_FIELD (x);
 	}
 
-      DECL_INITIAL (x) = 0;
-
       /* Detect flexible array member in an invalid context.  */
       if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
 	  && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
@@ -5023,12 +5023,20 @@ finish_struct (tree t, tree fieldlist, t
 
   layout_type (t);
 
-  /* Delete all zero-width bit-fields from the fieldlist.  */
+  /* Give bit-fields their proper types.  */
   {
     tree *fieldlistp = &fieldlist;
     while (*fieldlistp)
       if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp))
-	*fieldlistp = TREE_CHAIN (*fieldlistp);
+	{
+	  unsigned HOST_WIDE_INT width
+	    = tree_low_cst (DECL_INITIAL (*fieldlistp), 1);
+	  tree type = TREE_TYPE (*fieldlistp);
+	  if (width != TYPE_PRECISION (type))
+	    TREE_TYPE (*fieldlistp)
+	      = build_nonstandard_integer_type (width, TREE_UNSIGNED (type));
+	  DECL_INITIAL (*fieldlistp) = 0;
+	}
       else
 	fieldlistp = &TREE_CHAIN (*fieldlistp);
   }
diff -rupN GCC.orig/gcc/c-lang.c GCC/gcc/c-lang.c
--- GCC.orig/gcc/c-lang.c	2004-02-04 20:23:14.000000000 +0000
+++ GCC/gcc/c-lang.c	2004-03-15 23:20:59.000000000 +0000
@@ -75,6 +75,8 @@ enum c_language_kind c_language = clk_c;
 #define LANG_HOOKS_STATICP c_staticp
 #undef LANG_HOOKS_SET_DECL_ASSEMBLER_NAME
 #define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME c_static_assembler_name
+#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS
+#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS	true
 #undef LANG_HOOKS_NO_BODY_BLOCKS
 #define LANG_HOOKS_NO_BODY_BLOCKS true
 #undef LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL
diff -rupN GCC.orig/gcc/expr.c GCC/gcc/expr.c
--- GCC.orig/gcc/expr.c	2004-03-05 14:26:21.000000000 +0000
+++ GCC/gcc/expr.c	2004-03-15 23:25:01.000000000 +0000
@@ -162,6 +162,7 @@ static int is_aligning_offset (tree, tre
 static rtx expand_increment (tree, int, int);
 static void expand_operands (tree, tree, rtx, rtx*, rtx*,
 			     enum expand_modifier);
+static rtx reduce_to_bit_field_precision (rtx, rtx, tree);
 static rtx do_store_flag (tree, rtx, enum machine_mode, int);
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn (enum machine_mode, rtx, tree);
@@ -6215,6 +6216,12 @@ expand_expr_real (tree exp, rtx target, 
   rtx subtarget, original_target;
   int ignore;
   tree context;
+  bool reduce_bit_field = false;
+#define REDUCE_BIT_FIELD(expr)	(reduce_bit_field && !ignore		  \
+				 ? reduce_to_bit_field_precision ((expr), \
+								  target, \
+								  type)	  \
+				 : (expr))
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
   if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
@@ -6226,6 +6233,18 @@ expand_expr_real (tree exp, rtx target, 
     }
 
   mode = TYPE_MODE (type);
+  if (lang_hooks.reduce_bit_field_operations
+      && (TREE_CODE (type) == INTEGER_TYPE
+	  || TREE_CODE (type) == ENUMERAL_TYPE)
+      && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
+    {
+      /* An operation in what may be a bit-field type needs the
+	 result to be reduced to the precision of the bit-field type,
+	 which is narrower than that of the type's mode.  */
+      reduce_bit_field = true;
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
+    }
   /* Use subtarget as the target for operand 0 of a binary operation.  */
   subtarget = get_subtarget (target);
   original_target = target;
@@ -7551,10 +7570,11 @@ expand_expr_real (tree exp, rtx target, 
 	      && GET_CODE (op0) == SUBREG)
 	    SUBREG_PROMOTED_VAR_P (op0) = 0;
 
-	  return op0;
+	  return REDUCE_BIT_FIELD (op0);
 	}
 
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+      op0 = REDUCE_BIT_FIELD (op0);
       if (GET_MODE (op0) == mode)
 	return op0;
 
@@ -7722,7 +7742,7 @@ expand_expr_real (tree exp, rtx target, 
 	      op1 = plus_constant (op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
-	      return op1;
+	      return REDUCE_BIT_FIELD (op1);
 	    }
 
 	  else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
@@ -7755,7 +7775,7 @@ expand_expr_real (tree exp, rtx target, 
 	      op0 = plus_constant (op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
-	      return op0;
+	      return REDUCE_BIT_FIELD (op0);
 	    }
 	}
 
@@ -7777,7 +7797,7 @@ expand_expr_real (tree exp, rtx target, 
 
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
 		       subtarget, &op0, &op1, modifier);
-      return simplify_gen_binary (PLUS, mode, op0, op1);
+      return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
     case MINUS_EXPR:
       /* For initializers, we are allowed to return a MINUS of two
@@ -7795,9 +7815,9 @@ expand_expr_real (tree exp, rtx target, 
 	  /* If the last operand is a CONST_INT, use plus_constant of
 	     the negated constant.  Else make the MINUS.  */
 	  if (GET_CODE (op1) == CONST_INT)
-	    return plus_constant (op0, - INTVAL (op1));
+	    return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
 	  else
-	    return gen_rtx_MINUS (mode, op0, op1);
+	    return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
 	}
 
       this_optab = ! unsignedp && flag_trapv
@@ -7819,7 +7839,7 @@ expand_expr_real (tree exp, rtx target, 
       if (GET_CODE (op1) == CONST_INT)
 	{
 	  op1 = negate_rtx (mode, op1);
-	  return simplify_gen_binary (PLUS, mode, op0, op1);
+	  return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 	}
 
       goto binop2;
@@ -7851,9 +7871,9 @@ expand_expr_real (tree exp, rtx target, 
 	  if (GET_CODE (op0) != REG)
 	    op0 = copy_to_mode_reg (mode, op0);
 
-	  return gen_rtx_MULT (mode, op0,
+	  return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
 			       gen_int_mode (tree_low_cst (exp1, 0),
-					     TYPE_MODE (TREE_TYPE (exp1))));
+					     TYPE_MODE (TREE_TYPE (exp1)))));
 	}
 
       if (modifier == EXPAND_STACK_PARM)
@@ -7927,13 +7947,13 @@ expand_expr_real (tree exp, rtx target, 
 						      zextend_p);
 		  if (htem != hipart)
 		    emit_move_insn (hipart, htem);
-		  return temp;
+		  return REDUCE_BIT_FIELD (temp);
 		}
 	    }
 	}
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
 		       subtarget, &op0, &op1, 0);
-      return expand_mult (mode, op0, op1, target, unsignedp);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
     case TRUNC_DIV_EXPR:
     case FLOOR_DIV_EXPR:
@@ -8009,7 +8029,7 @@ expand_expr_real (tree exp, rtx target, 
 			  ? negv_optab : neg_optab, op0, target, 0);
       if (temp == 0)
 	abort ();
-      return temp;
+      return REDUCE_BIT_FIELD (temp);
 
     case ABS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
@@ -8719,12 +8739,12 @@ expand_expr_real (tree exp, rtx target, 
 
     case PREINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
-      return expand_increment (exp, 0, ignore);
+      return REDUCE_BIT_FIELD (expand_increment (exp, 0, ignore));
 
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       /* Faster to treat as pre-increment if result is not used.  */
-      return expand_increment (exp, ! ignore, ignore);
+      return REDUCE_BIT_FIELD (expand_increment (exp, ! ignore, ignore));
 
     case ADDR_EXPR:
       if (modifier == EXPAND_STACK_PARM)
@@ -9076,7 +9096,37 @@ expand_expr_real (tree exp, rtx target, 
 		       unsignedp, OPTAB_LIB_WIDEN);
   if (temp == 0)
     abort ();
-  return temp;
+  return REDUCE_BIT_FIELD (temp);
+}
+#undef REDUCE_BIT_FIELD
+
+/* Subroutine of above: reduce EXP to the precision of TYPE (in the
+   signedness of TYPE), possibly returning the result in TARGET.  */
+static rtx
+reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
+{
+  HOST_WIDE_INT prec = TYPE_PRECISION (type);
+  if (target && GET_MODE (target) != GET_MODE (exp))
+    target = 0;
+  if (TREE_UNSIGNED (type))
+    {
+      rtx mask;
+      if (prec < HOST_BITS_PER_WIDE_INT)
+	mask = immed_double_const (((unsigned HOST_WIDE_INT) 1 << prec) - 1, 0,
+				   GET_MODE (exp));
+      else
+	mask = immed_double_const ((unsigned HOST_WIDE_INT) -1,
+				   ((unsigned HOST_WIDE_INT) 1
+				    << (prec - HOST_BITS_PER_WIDE_INT)) - 1,
+				   GET_MODE (exp));
+      return expand_and (GET_MODE (exp), exp, mask, target);
+    }
+  else
+    {
+      tree count = build_int_2 (GET_MODE_BITSIZE (GET_MODE (exp)) - prec, 0);
+      exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
+      return expand_shift (RSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
+    }
 }
 
 /* Subroutine of above: returns 1 if OFFSET corresponds to an offset that
diff -rupN GCC.orig/gcc/langhooks-def.h GCC/gcc/langhooks-def.h
--- GCC.orig/gcc/langhooks-def.h	2004-03-04 09:59:58.000000000 +0000
+++ GCC/gcc/langhooks-def.h	2004-03-15 23:19:44.000000000 +0000
@@ -111,6 +111,7 @@ extern tree lhd_callgraph_analyze_expr (
 #define LANG_HOOKS_MAYBE_BUILD_CLEANUP	lhd_return_null_tree
 #define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME lhd_set_decl_assembler_name
 #define LANG_HOOKS_CAN_USE_BIT_FIELDS_P lhd_can_use_bit_fields_p
+#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS false
 #define LANG_HOOKS_HONOR_READONLY	false
 #define LANG_HOOKS_NO_BODY_BLOCKS	false
 #define LANG_HOOKS_PRINT_STATISTICS	lhd_do_nothing
@@ -290,6 +291,7 @@ extern tree lhd_make_node (enum tree_cod
   LANG_HOOKS_MAYBE_BUILD_CLEANUP, \
   LANG_HOOKS_SET_DECL_ASSEMBLER_NAME, \
   LANG_HOOKS_CAN_USE_BIT_FIELDS_P, \
+  LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS, \
   LANG_HOOKS_HONOR_READONLY, \
   LANG_HOOKS_NO_BODY_BLOCKS, \
   LANG_HOOKS_PRINT_STATISTICS, \
diff -rupN GCC.orig/gcc/langhooks.h GCC/gcc/langhooks.h
--- GCC.orig/gcc/langhooks.h	2004-02-13 01:01:30.000000000 +0000
+++ GCC/gcc/langhooks.h	2004-03-15 23:19:03.000000000 +0000
@@ -345,6 +345,10 @@ struct lang_hooks
      optimizations, for instance in fold_truthop().  */
   bool (*can_use_bit_fields_p) (void);
 
+  /* Nonzero if operations on types narrower than their mode should
+     have their results reduced to the precision of the type.  */
+  bool reduce_bit_field_operations;
+
   /* Nonzero if TYPE_READONLY and TREE_READONLY should always be honored.  */
   bool honor_readonly;
 
diff -rupN GCC.orig/gcc/objc/objc-act.c GCC/gcc/objc/objc-act.c
--- GCC.orig/gcc/objc/objc-act.c	2004-03-06 11:10:06.000000000 +0000
+++ GCC/gcc/objc/objc-act.c	2004-03-06 23:41:51.000000000 +0000
@@ -4268,6 +4268,16 @@ check_ivars (tree inter, tree imp)
 
       t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
 
+      if (TREE_VALUE (TREE_VALUE (rawimpdecls)))
+	{
+	  /* t1 is the bit-field type, so t2 must be converted to the
+	     bit-field type for comparison as well.  */
+	  unsigned HOST_WIDE_INT width
+	    = tree_low_cst (TREE_VALUE (TREE_VALUE (rawimpdecls)), 1);
+	  if (width != TYPE_PRECISION (t2))
+	    t2 = build_nonstandard_integer_type (width, TREE_UNSIGNED (t2));
+	}
+
       if (!comptypes (t1, t2, false)
 	  || !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)),
 				  TREE_VALUE (TREE_VALUE (rawimpdecls))))
diff -rupN GCC.orig/gcc/objc/objc-lang.c GCC/gcc/objc/objc-lang.c
--- GCC.orig/gcc/objc/objc-lang.c	2004-02-04 20:23:43.000000000 +0000
+++ GCC/gcc/objc/objc-lang.c	2004-03-15 23:21:16.000000000 +0000
@@ -1,5 +1,5 @@
 /* Language-dependent hooks for Objective-C.
-   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Ziemowit Laski  <zlaski@apple.com>
 
 This file is part of GCC.
@@ -69,6 +69,8 @@ enum c_language_kind c_language = clk_ob
 #define LANG_HOOKS_STATICP c_staticp
 #undef LANG_HOOKS_SET_DECL_ASSEMBLER_NAME
 #define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME c_static_assembler_name
+#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS
+#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS	true
 #undef LANG_HOOKS_NO_BODY_BLOCKS
 #define LANG_HOOKS_NO_BODY_BLOCKS true
 #undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
diff -rupN GCC.orig/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x GCC/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x
--- GCC.orig/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x	2002-02-02 00:14:41.000000000 +0000
+++ GCC/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-set torture_execute_xfail "*-*-*"
-return 0
diff -rupN GCC.orig/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c GCC/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c
--- GCC.orig/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c	2004-03-06 23:41:51.000000000 +0000
@@ -0,0 +1,54 @@
+/* Test that operations on bit-fields yield results reduced to bit-field
+   type.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+
+extern void exit (int);
+extern void abort (void);
+
+struct s {
+  unsigned long long u33: 33;
+  unsigned long long u40: 40;
+  unsigned long long u41: 41;
+};
+
+struct s a = { 0x100000, 0x100000, 0x100000 };
+struct s b = { 0x100000000ULL, 0x100000000ULL, 0x100000000ULL };
+struct s c = { 0x1FFFFFFFFULL, 0, 0 };
+
+int 
+main (void)
+{
+  if (a.u33 * a.u33 != 0 || a.u33 * a.u40 != 0 || a.u40 * a.u33 != 0
+      || a.u40 * a.u40 != 0)
+    abort ();
+  if (a.u33 * a.u41 != 0x10000000000ULL
+      || a.u40 * a.u41 != 0x10000000000ULL
+      || a.u41 * a.u33 != 0x10000000000ULL
+      || a.u41 * a.u40 != 0x10000000000ULL
+      || a.u41 * a.u41 != 0x10000000000ULL)
+    abort ();
+  if (b.u33 + b.u33 != 0)
+    abort ();
+  if (b.u33 + b.u40 != 0x200000000ULL
+      || b.u33 + b.u41 != 0x200000000ULL
+      || b.u40 + b.u33 != 0x200000000ULL
+      || b.u40 + b.u40 != 0x200000000ULL
+      || b.u40 + b.u41 != 0x200000000ULL
+      || b.u41 + b.u33 != 0x200000000ULL
+      || b.u41 + b.u40 != 0x200000000ULL
+      || b.u41 + b.u41 != 0x200000000ULL)
+    abort ();
+  if (a.u33 - b.u33 != 0x100100000ULL
+      || a.u33 - b.u40 != 0xFF00100000ULL
+      || a.u33 - b.u41 != 0x1FF00100000ULL
+      || a.u40 - b.u33 != 0xFF00100000ULL
+      || a.u40 - b.u40 != 0xFF00100000ULL
+      || a.u40 - b.u41 != 0x1FF00100000ULL
+      || a.u41 - b.u33 != 0x1FF00100000ULL
+      || a.u41 - b.u40 != 0x1FF00100000ULL
+      || a.u41 - b.u41 != 0x1FF00100000ULL)
+    abort ();
+  if (++c.u33 != 0 || --c.u40 != 0xFFFFFFFFFFULL || c.u41-- != 0)
+    abort ();
+  exit (0);
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/bitfld-2.c GCC/gcc/testsuite/gcc.dg/bitfld-2.c
--- GCC.orig/gcc/testsuite/gcc.dg/bitfld-2.c	2002-02-02 01:35:30.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/bitfld-2.c	2004-03-06 23:41:51.000000000 +0000
@@ -11,13 +11,13 @@ struct bf
   int b: 2;
 };
 
-struct bf p = {4, 0};		/* { dg-warning "truncated" "" { xfail *-*-* } } */
-struct bf q = {0, 2};		/* { dg-warning "overflow" "" { xfail *-*-* } } */
+struct bf p = {4, 0};		/* { dg-warning "truncated" "" } */
+struct bf q = {0, 2};		/* { dg-warning "overflow" "" } */
 struct bf r = {3, -2};		/* { dg-bogus "(truncated|overflow)" } */
 
 void foo ()
 {
-  p.a = 4, p.b = 0;		/* { dg-warning "truncated" "" { xfail *-*-* } } */
-  q.a = 0, q.b = 2;		/* { dg-warning "overflow" "" { xfail *-*-* } } */
+  p.a = 4, p.b = 0;		/* { dg-warning "truncated" "" } */
+  q.a = 0, q.b = 2;		/* { dg-warning "overflow" "" } */
   r.a = 3, r.b = -2;		/* { dg-bogus "(truncated|overflow)" } */
 }
diff -rupN GCC.orig/gcc/tree.c GCC/gcc/tree.c
--- GCC.orig/gcc/tree.c	2004-03-06 11:10:03.000000000 +0000
+++ GCC/gcc/tree.c	2004-03-06 23:41:51.000000000 +0000
@@ -3907,6 +3907,28 @@ build_index_type (tree maxval)
     return itype;
 }
 
+/* Builds a signed or unsigned integer type of precision PRECISION.
+   Used for C bitfields whose precision does not match that of
+   built-in target types.  */
+tree
+build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision,
+				int unsignedp)
+{
+  tree itype = make_node (INTEGER_TYPE);
+
+  TYPE_PRECISION (itype) = precision;
+
+  if (unsignedp)
+    fixup_unsigned_type (itype);
+  else
+    fixup_signed_type (itype);
+
+  if (host_integerp (TYPE_MAX_VALUE (itype), 1))
+    return type_hash_canon (tree_low_cst (TYPE_MAX_VALUE (itype), 1), itype);
+
+  return itype;
+}
+
 /* Create a range of some discrete type TYPE (an INTEGER_TYPE,
    ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with
    low bound LOWVAL and high bound HIGHVAL.
diff -rupN GCC.orig/gcc/tree.h GCC/gcc/tree.h
--- GCC.orig/gcc/tree.h	2004-03-06 11:10:03.000000000 +0000
+++ GCC/gcc/tree.h	2004-03-06 23:41:51.000000000 +0000
@@ -2899,6 +2899,7 @@ extern int real_minus_onep (tree);
 extern void init_ttree (void);
 extern void build_common_tree_nodes (int);
 extern void build_common_tree_nodes_2 (int);
+extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree build_range_type (tree, tree, tree);
 
 /* In function.c */

-- 
Joseph S. Myers
jsm@polyomino.org.uk


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