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]

[tree-ssa] CCP for bitfields [patch]


This patch hacks CCP to recognize bitfields and zero/sign extend
the values appropriately.  It fixes all the current regressions
with constant propagating bitfield constants, but it feels
hackish.

I'd like opinions on the approach.  Essentially, when we are
evaluating a new constant and find that it's for a bitfield, we
emit code to deal with the sign bit and fold that.

I think the approach is target independent, but I'm not too sure
if this operation is language independent.  I'd like folks more
familiar with different front ends to give their opinion.

Bootstrapped and tested on x86.  Other targets are still in
progress.


Thanks.  Diego.


	* tree-ssa-ccp.c (widen_bitfield): New function.
	(evaluate_expr_for): Call it.

Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.9
diff -d -u -p -r1.1.2.9 tree-ssa-ccp.c
--- tree-ssa-ccp.c	18 Aug 2002 15:14:45 -0000	1.1.2.9
+++ tree-ssa-ccp.c	19 Aug 2002 01:37:02 -0000
@@ -128,6 +128,7 @@ static void ssa_ccp_substitute_constants
 static void ssa_ccp_df_delete_unreachable_insns PARAMS ((void));
 static value evaluate_expr_for         PARAMS ((varref));
 static void dump_lattice_value         PARAMS ((FILE *, const char *, value));
+static tree widen_bitfield             PARAMS ((tree, tree, tree));
 
 /* Debugging dumps.  */
 static FILE *dump_file;
@@ -852,6 +853,24 @@ evaluate_expr_for (ref)
     {
       val.lattice_val = CONSTANT;
       val.const_value = simplified;
+
+      /* FIXME: Hack.  If this was a definition of a bitfield, we need to
+	        widen the constant value into the type of the destination
+		variable.  This should not be necessary if GCC represented
+		bitfields properly.  */
+      if (TREE_CODE (var) == COMPONENT_REF
+	  && DECL_BIT_FIELD (TREE_OPERAND (var, 1)))
+	{
+	  tree w = widen_bitfield (simplified, TREE_OPERAND (var, 1), var);
+
+	  if (w)
+	    val.const_value = w;
+	  else
+	    {
+	      val.lattice_val = VARYING;
+	      val.const_value = NULL;
+	    }
+	}
     }
 
   /* Restore the expression to its original form.  */
@@ -903,4 +922,61 @@ dump_lattice_value (outf, prefix, val)
       fprintf (outf, "%sCONSTANT ", prefix);
       print_c_node (outf, val.const_value);
     }
+}
+
+/* Given a constant value VAL for bitfield FIELD, and a destination
+   variable VAR, return VAL appropriately widened to fit into VAR.  If
+   FIELD is wider than HOST_WIDE_INT, NULL is returned.  */
+
+static tree
+widen_bitfield (val, field, var)
+     tree val;
+     tree field;
+     tree var;
+{
+  unsigned var_size, field_size;
+  tree ret, wide_val;
+  unsigned HOST_WIDE_INT v, mask;
+  unsigned i;
+
+  var_size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE ((var))));
+  field_size = TREE_INT_CST_LOW (DECL_SIZE (field));
+
+  /* Give up if either the bitfield or the variable are too wide.  */
+  if (field_size > HOST_BITS_PER_WIDE_INT || var_size > HOST_BITS_PER_WIDE_INT)
+    return NULL;
+
+#ifdef ENABLE_CHECKING
+  if (var_size < field_size)
+    abort ();
+#endif
+
+  /* If the sign bit of the value is not set, return it unmodified.  */
+  if ((TREE_INT_CST_LOW (val) & (1 << (field_size - 1))) == 0)
+    return val;
+
+  if (TREE_UNSIGNED (field))
+    {
+      /* Zero extension.  Build a mask with the lower 'field_size' bits
+	 set and a BIT_AND_EXPR node to clear the high order bits of
+	 the value.  */
+      for (i = 0, mask = 0; i < field_size; i++)
+	mask |= 1 << i;
+
+      wide_val = build (BIT_AND_EXPR, TREE_TYPE (var), val, 
+			build_int_2 (mask, 0));
+    }
+  else
+    {
+      /* Sign extension.  Create a mask with the upper 'field_size'
+	 bits set and a BIT_IOR_EXPR to set the high order bits of the
+	 value.  */
+      for (i = 0, mask = 0; i < (var_size - field_size); i++)
+	mask |= 1 << (var_size - i - 1);
+
+      wide_val = build (BIT_IOR_EXPR, TREE_TYPE (var), val,
+			build_int_2 (mask, 0));
+    }
+
+  return fold (wide_val);
 }


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