Patchwork Add a new option "-ftree-bitfield-merge" (patch / doc inside)

login
register
mail settings
Submitter Zoran Jovanovic
Date March 9, 2014, 8:35 p.m.
Message ID <386B40EC5E8DBF459FD11A754D868AD96DA5A28A@BADAG02.ba.imgtec.org>
Download mbox | patch
Permalink /patch/328396/
State New
Headers show

Comments

Zoran Jovanovic - March 9, 2014, 8:35 p.m.
Hello,
This is new patch version. 
Approach suggested by Richard Biener with lowering bit-field accesses instead of modifying gimple trees is implemented.
Although, algorithm still detects adjacent bit field accesses, which copy values from one to another bit-field of same type.
If those accesses are detected field size used during lowering is equal to sum of sizes of all adjacent fields that can be merged. 
Idea is to let dse and cse to remove unnecessary instructions afterwards.
I wanted to preserve this behavior because it was one of original goals of this work.


Example:

Original code:
  <bb 2>:
  _2 = pr1.f1;
  pr2.f1 = _2;
  _4 = pr1.f2;
  pr2.f2 = _4;
  _6 = pr1.f3;
  pr2.f3 = _6;
  return;


Optimized code:
  <bb 2>:
  _8 = pr1.D.1364;
  _9 = BIT_FIELD_REF <_8, 13, 0>;
  _10 = pr2.D.1364;
  _11 = _10 & 4294959104;
  _12 = (unsigned int) _9;
  _13 = _11 | _12;
  pr2.D.1364 = _13;
  _14 = pr1.D.1364;
  _15 = BIT_FIELD_REF <_14, 13, 0>;
  _16 = pr2.D.1364;
  _17 = _16 & 4294959104;
  _18 = (unsigned int) _15;
  _19 = _17 | _18;
  pr2.D.1364 = _19;
  _20 = pr1.D.1364;
  _21 = BIT_FIELD_REF <_20, 13, 0>;
  _22 = pr2.D.1364;
  _23 = _22 & 4294959104;
  _24 = (unsigned int) _21;
  _25 = _23 | _24;
  pr2.D.1364 = _25;
  return;
  

Algorithm works on basic block level and consists of following 3 major steps:
1. Go through basic block statements list. If there are statement pairs that implement copy of bit field content from one memory location to another record statements pointers and other necessary data in corresponding data structure.
2. Identify records that represent adjacent bit field accesses and mark them as merged.
3. Lower bit-field accesses by using new field size for those that can be merged.


New command line option "-fmerge-bitfields" is introduced.

Tested - passed gcc regression tests.

Changelog -

gcc/ChangeLog:
2014-03-09 Zoran Jovanovic (zoran.jovanovic@imgtec.com)
  * common.opt (fmerge-bitfields): New option.
  * doc/invoke.texi: Added reference to "-fmerge-bitfields".
  * tree-sra.c (lower_bitfields): New function.
  Entry for (-fmerge-bitfields).
  (bfaccess::hash): New function.
  (bfaccess::equal): New function.
  (bfaccess::remove): New function.
  (bitfield_access_p): New function.
  (lower_bitfield_read): New function.
  (lower_bitfield_write): New function.
  (bitfield_stmt_access_pair_htab_hash): New function.
  (bitfield_stmt_access_pair_htab_eq): New function.
  (create_and_insert_access): New function.
  (get_bit_offset): New function.
  (get_merged_bit_field_size): New function.
  (add_stmt_access_pair): New function.
  (cmp_access): New function.
  * dwarf2out.c (simple_type_size_in_bits): moved to tree.c.
  (field_byte_offset): declaration moved to tree.h, static removed.
  * testsuite/gcc.dg/tree-ssa/bitfldmrg1.c: New test.
  * testsuite/gcc.dg/tree-ssa/bitfldmrg2.c: New test.
  * tree-ssa-sccvn.c (expressions_equal_p): moved to tree.c.
  * tree-ssa-sccvn.h (expressions_equal_p): declaration moved to tree.h.
  * tree.c (expressions_equal_p): moved from tree-ssa-sccvn.c.
  (simple_type_size_in_bits): moved from dwarf2out.c.
  * tree.h (expressions_equal_p): declaration added.
  (field_byte_offset): declaration added.

Patch -




Regards,
Zoran Jovanovic
aldot - March 12, 2014, 9:45 p.m.
On Sun, Mar 09, 2014 at 08:35:43PM +0000, Zoran Jovanovic wrote:
> Hello,
> This is new patch version. 
> Approach suggested by Richard Biener with lowering bit-field accesses instead of modifying gimple trees is implemented.
 
> New command line option "-fmerge-bitfields" is introduced.
> 
> Tested - passed gcc regression tests.
> 
> Changelog -
> 
> gcc/ChangeLog:
> 2014-03-09 Zoran Jovanovic (zoran.jovanovic@imgtec.com)
>   * common.opt (fmerge-bitfields): New option.
>   * doc/invoke.texi: Added reference to "-fmerge-bitfields".

Present tense.

>   * tree-sra.c (lower_bitfields): New function.
>   Entry for (-fmerge-bitfields).
>   (bfaccess::hash): New function.
>   (bfaccess::equal): New function.
>   (bfaccess::remove): New function.
>   (bitfield_access_p): New function.
>   (lower_bitfield_read): New function.
>   (lower_bitfield_write): New function.
>   (bitfield_stmt_access_pair_htab_hash): New function.
>   (bitfield_stmt_access_pair_htab_eq): New function.
>   (create_and_insert_access): New function.
>   (get_bit_offset): New function.
>   (get_merged_bit_field_size): New function.
>   (add_stmt_access_pair): New function.
>   (cmp_access): New function.
>   * dwarf2out.c (simple_type_size_in_bits): moved to tree.c.

Present tense. Capital 'M'ove

>   (field_byte_offset): declaration moved to tree.h, static removed.

Capital 'D'eclaration. These are supposed to be sentences. By removing
static you IMHO 'make extern'.

>   * testsuite/gcc.dg/tree-ssa/bitfldmrg1.c: New test.
>   * testsuite/gcc.dg/tree-ssa/bitfldmrg2.c: New test.
>   * tree-ssa-sccvn.c (expressions_equal_p): moved to tree.c.

See above.

>   * tree-ssa-sccvn.h (expressions_equal_p): declaration moved to tree.h.

Likewise.

>   * tree.c (expressions_equal_p): moved from tree-ssa-sccvn.c.

See above.

>   (simple_type_size_in_bits): moved from dwarf2out.c.

See above.

>   * tree.h (expressions_equal_p): declaration added.

Ditto.

>   (field_byte_offset): declaration added.

Ditto.

> 
> Patch -
> 
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 661516d..3331d03 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2193,6 +2193,10 @@ ftree-sra
>  Common Report Var(flag_tree_sra) Optimization
>  Perform scalar replacement of aggregates
>  
> +fmerge-bitfields
> +Common Report Var(flag_tree_bitfield_merge) Init(0) Optimization

Optimization but not enabled for any level. So, where would one
generally want this enabled? CSiBE numbers? SPEC you-name-it
improvements? size(1) improvements where? In GCC there is generally no
interest in the size(1) added to the collection itself, so let me ask
for size(1) and bloat(-o-meter) stats for gcc, cc1 and collect2, just
for the sake of it?

> +Merge loads and stores of consecutive bitfields
> +
>  ftree-ter
>  Common Report Var(flag_tree_ter) Optimization
>  Replace temporary expressions in the SSA->normal pass
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 24bd76e..54bae56 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -411,7 +411,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fsplit-ivs-in-unroller -fsplit-wide-types -fstack-protector @gol
>  -fstack-protector-all -fstack-protector-strong -fstrict-aliasing @gol
>  -fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp @gol
> --ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol
> +-fmerge-bitfields -ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol
>  -ftree-coalesce-inline-vars -ftree-coalesce-vars -ftree-copy-prop @gol
>  -ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse @gol
>  -ftree-forwprop -ftree-fre -ftree-loop-if-convert @gol
> @@ -7807,6 +7807,11 @@ pointer alignment information.
>  This pass only operates on local scalar variables and is enabled by default
>  at @option{-O} and higher.  It requires that @option{-ftree-ccp} is enabled.
>  
> +@item -fbitfield-merge

you are talking about '-fmerge-bitfields' up until here (except for
Subject. [Confusion starts here -- Subject: -ftree-bitfield-merge; sofar
Intro -fmerge-bitfields and ChangeLog -fmerge-bitfields]

> +@opindex fmerge-bitfields
> +Combines several adjacent bit-field accesses that copy values
> +from one memory location to another into one single bit-field access.
> +
>  @item -ftree-ccp
>  @opindex ftree-ccp
>  Perform sparse conditional constant propagation (CCP) on trees.  This

> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
> index 284d544..c6a19b2 100644
> --- a/gcc/tree-sra.c
> +++ b/gcc/tree-sra.c
> @@ -3462,10 +3462,608 @@ perform_intra_sra (void)
>    return ret;
>  }
>  
> +/* Bitfield access and hashtable support commoning same base and
> +   representative.  */
> +
> +struct bfaccess
> +{
> +  bfaccess (tree r):ref (r), r_count (1), w_count (1), merged (false),
> +    modified (false), is_barrier (false), next (0), head_access (0)
> +  {
> +  }
> +
> +  tree ref;
> +  unsigned r_count;  /* Read counter.  */
> +  unsigned w_count;  /* Write counter.  */
> +
> +  /* hash_table support.  */
> +  typedef bfaccess value_type;
> +  typedef bfaccess compare_type;
> +  static inline hashval_t hash (const bfaccess *);

I suspect there's a reason to not have the * be a const* ?

> +  static inline int equal (const bfaccess *, const bfaccess *);

..which holds true here as well.

> +  static inline void remove (bfaccess *);
> +
> +  gimple load_stmt;		/* Bit-field load statement.  */
> +  gimple store_stmt;		/* Bit-field store statement.  */
> +  unsigned src_offset_words;	/* Bit-field offset at src in words.  */
> +  unsigned src_bit_offset;	/* Bit-field offset inside source word.  */
> +  unsigned src_bit_size;	/* Size of bit-field in source word.  */
> +  unsigned dst_offset_words;	/* Bit-field offset at dst in words.  */
> +  unsigned dst_bit_offset;	/* Bit-field offset inside destination
> +				   word.  */
> +  unsigned src_field_offset;	/* Source field offset.  */
> +  unsigned dst_bit_size;	/* Size of bit-field in destination word.  */
> +  tree src_addr;		/* Address of source memory access.  */
> +  tree dst_addr;		/* Address of destination memory access.  */
> +  bool merged;			/* True if access is merged with another
> +				   one.  */
> +  bool modified;		/* True if bit-field size is modified.  */
> +  bool is_barrier;		/* True if access is barrier (call or mem
> +				   access).  */

Back then the above usually were bitfields:1 themselves and for space
considerations were moved to a place where alignment begged for or with
cacheline friendliness in mind but i guess those times are past
nowadays, yes?

> +  struct bfaccess *next;	/* Access with which this one is merged.  */
> +  tree bitfield_representative;	/* Bit field representative of original
> +				   declaration.  */
> +  struct bfaccess *head_access;	/* Head of access list where this one is
> +				   merged.  */
> +};

> +/* Return whether REF is a bitfield access the bit offset of the bitfield

mhm. Maybe it's late here by now, but can you actually parse the
sentence above? Is there an 'at' missing somewhere?
"a bitfield access at" perhaps?

Here I'll stop attempts to follow what you wrote, no offence.

TIA && cheers,

Patch

diff --git a/gcc/common.opt b/gcc/common.opt
index 661516d..3331d03 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2193,6 +2193,10 @@  ftree-sra
 Common Report Var(flag_tree_sra) Optimization
 Perform scalar replacement of aggregates
 
+fmerge-bitfields
+Common Report Var(flag_tree_bitfield_merge) Init(0) Optimization
+Merge loads and stores of consecutive bitfields
+
 ftree-ter
 Common Report Var(flag_tree_ter) Optimization
 Replace temporary expressions in the SSA->normal pass
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 24bd76e..54bae56 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -411,7 +411,7 @@  Objective-C and Objective-C++ Dialects}.
 -fsplit-ivs-in-unroller -fsplit-wide-types -fstack-protector @gol
 -fstack-protector-all -fstack-protector-strong -fstrict-aliasing @gol
 -fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp @gol
--ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol
+-fmerge-bitfields -ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol
 -ftree-coalesce-inline-vars -ftree-coalesce-vars -ftree-copy-prop @gol
 -ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse @gol
 -ftree-forwprop -ftree-fre -ftree-loop-if-convert @gol
@@ -7807,6 +7807,11 @@  pointer alignment information.
 This pass only operates on local scalar variables and is enabled by default
 at @option{-O} and higher.  It requires that @option{-ftree-ccp} is enabled.
 
+@item -fbitfield-merge
+@opindex fmerge-bitfields
+Combines several adjacent bit-field accesses that copy values
+from one memory location to another into one single bit-field access.
+
 @item -ftree-ccp
 @opindex ftree-ccp
 Perform sparse conditional constant propagation (CCP) on trees.  This
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 2b584a5..5150d40 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3119,8 +3119,6 @@  static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
 static tree field_type (const_tree);
 static unsigned int simple_type_align_in_bits (const_tree);
 static unsigned int simple_decl_align_in_bits (const_tree);
-static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
-static HOST_WIDE_INT field_byte_offset (const_tree);
 static void add_AT_location_description	(dw_die_ref, enum dwarf_attribute,
 					 dw_loc_list_ref);
 static void add_data_member_location_attribute (dw_die_ref, tree);
@@ -10281,25 +10279,6 @@  is_base_type (tree type)
   return 0;
 }
 
-/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
-   node, return the size in bits for the type if it is a constant, or else
-   return the alignment for the type if the type's size is not constant, or
-   else return BITS_PER_WORD if the type actually turns out to be an
-   ERROR_MARK node.  */
-
-static inline unsigned HOST_WIDE_INT
-simple_type_size_in_bits (const_tree type)
-{
-  if (TREE_CODE (type) == ERROR_MARK)
-    return BITS_PER_WORD;
-  else if (TYPE_SIZE (type) == NULL_TREE)
-    return 0;
-  else if (tree_fits_uhwi_p (TYPE_SIZE (type)))
-    return tree_to_uhwi (TYPE_SIZE (type));
-  else
-    return TYPE_ALIGN (type);
-}
-
 /* Similarly, but return a double_int instead of UHWI.  */
 
 static inline double_int
@@ -14667,7 +14646,7 @@  round_up_to_align (double_int t, unsigned int align)
    because the offset is actually variable.  (We can't handle the latter case
    just yet).  */
 
-static HOST_WIDE_INT
+HOST_WIDE_INT
 field_byte_offset (const_tree decl)
 {
   double_int object_offset_in_bits;
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 284d544..c6a19b2 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -3462,10 +3462,608 @@  perform_intra_sra (void)
   return ret;
 }
 
+/* Bitfield access and hashtable support commoning same base and
+   representative.  */
+
+struct bfaccess
+{
+  bfaccess (tree r):ref (r), r_count (1), w_count (1), merged (false),
+    modified (false), is_barrier (false), next (0), head_access (0)
+  {
+  }
+
+  tree ref;
+  unsigned r_count;  /* Read counter.  */
+  unsigned w_count;  /* Write counter.  */
+
+  /* hash_table support.  */
+  typedef bfaccess value_type;
+  typedef bfaccess compare_type;
+  static inline hashval_t hash (const bfaccess *);
+  static inline int equal (const bfaccess *, const bfaccess *);
+  static inline void remove (bfaccess *);
+
+  gimple load_stmt;		/* Bit-field load statement.  */
+  gimple store_stmt;		/* Bit-field store statement.  */
+  unsigned src_offset_words;	/* Bit-field offset at src in words.  */
+  unsigned src_bit_offset;	/* Bit-field offset inside source word.  */
+  unsigned src_bit_size;	/* Size of bit-field in source word.  */
+  unsigned dst_offset_words;	/* Bit-field offset at dst in words.  */
+  unsigned dst_bit_offset;	/* Bit-field offset inside destination
+				   word.  */
+  unsigned src_field_offset;	/* Source field offset.  */
+  unsigned dst_bit_size;	/* Size of bit-field in destination word.  */
+  tree src_addr;		/* Address of source memory access.  */
+  tree dst_addr;		/* Address of destination memory access.  */
+  bool merged;			/* True if access is merged with another
+				   one.  */
+  bool modified;		/* True if bit-field size is modified.  */
+  bool is_barrier;		/* True if access is barrier (call or mem
+				   access).  */
+  struct bfaccess *next;	/* Access with which this one is merged.  */
+  tree bitfield_representative;	/* Bit field representative of original
+				   declaration.  */
+  struct bfaccess *head_access;	/* Head of access list where this one is
+				   merged.  */
+};
+
+hashval_t bfaccess::hash (const bfaccess * a)
+{
+  return iterative_hash_hashval_t
+    (iterative_hash_expr (TREE_OPERAND (a->ref, 0), 0),
+     DECL_UID (DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (a->ref, 1))));
+}
+
+int
+bfaccess::equal (const bfaccess * a, const bfaccess * b)
+{
+  return ((DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (a->ref, 1))
+	   == DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (b->ref, 1)))
+	  && operand_equal_p (TREE_OPERAND (a->ref, 0),
+			      TREE_OPERAND (b->ref, 0), 0));
+}
+
+void
+bfaccess::remove (bfaccess * a)
+{
+  delete a;
+}
+
+/* Return whether REF is a bitfield access the bit offset of the bitfield
+   within the representative in *OFF if that is not NULL.  */
+
+static bool
+bitfield_access_p (tree ref, unsigned HOST_WIDE_INT * off)
+{
+  if (TREE_CODE (ref) != COMPONENT_REF)
+    return false;
+
+  tree field = TREE_OPERAND (ref, 1);
+  if (!DECL_BIT_FIELD_TYPE (field))
+    return false;
+
+  tree rep = DECL_BIT_FIELD_REPRESENTATIVE (field);
+  if (!rep)
+    return false;
+
+  if (!off)
+    return true;
+
+  if (tree_fits_uhwi_p (DECL_FIELD_OFFSET (field))
+      && tree_fits_uhwi_p (DECL_FIELD_OFFSET (rep)))
+    *off = (tree_to_uhwi (DECL_FIELD_OFFSET (field))
+	    - tree_to_uhwi (DECL_FIELD_OFFSET (rep))) * BITS_PER_UNIT;
+  else
+    *off = 0;
+  *off += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field))
+	   - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (rep)));
+
+  return true;
+}
+
+
+/* Lower the bitfield read at *GSI, the offset of the bitfield
+   relative to the bitfield representative is OFF bits.  */
+#include "gimple-pretty-print.h"
+static void
+lower_bitfield_read (gimple_stmt_iterator * gsi, unsigned HOST_WIDE_INT off,
+		     tree size, tree type)
+{
+  //debug_tree (size);
+  gimple stmt = gsi_stmt (*gsi);
+  tree ref = gimple_assign_rhs1 (stmt);
+  tree field = TREE_OPERAND (ref, 1);
+  tree rep = DECL_BIT_FIELD_REPRESENTATIVE (field);
+
+  tree loadres = make_ssa_name (TREE_TYPE (rep), NULL);
+  gimple load = gimple_build_assign (loadres,
+				     build3 (COMPONENT_REF, TREE_TYPE (rep),
+					     TREE_OPERAND (ref, 0), rep,
+					     NULL_TREE));
+  gimple_set_vuse (load, gimple_vuse (stmt));
+  gsi_insert_before (gsi, load, GSI_SAME_STMT);
+  if (!type)
+    type = TREE_TYPE (ref);
+  gimple_assign_set_rhs1 (stmt,
+			  build3 (BIT_FIELD_REF, type,
+				  loadres, size, bitsize_int (off)));
+  update_stmt (stmt);
+}
+
+/* Lower the bitfield write at *GSI, the offset of the bitfield
+   relative to the bitfield representative is OFF bits.  */
+
+static void
+lower_bitfield_write (gimple_stmt_iterator * gsi, unsigned HOST_WIDE_INT off,
+		      tree size)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree ref = gimple_assign_lhs (stmt);
+  tree field = TREE_OPERAND (ref, 1);
+  tree rep = DECL_BIT_FIELD_REPRESENTATIVE (field);
+
+  tree loadres = make_ssa_name (TREE_TYPE (rep), NULL);
+  gimple load = gimple_build_assign (loadres,
+				     build3 (COMPONENT_REF, TREE_TYPE (rep),
+					     unshare_expr
+					     (TREE_OPERAND (ref, 0)),
+					     rep,
+					     NULL_TREE));
+  gimple_set_vuse (load, gimple_vuse (stmt));
+  gsi_insert_before (gsi, load, GSI_SAME_STMT);
+  /* FIXME:  BIT_FIELD_EXPR.  */
+  /* Mask out bits.  */
+  tree masked = make_ssa_name (TREE_TYPE (rep), NULL);
+  tree mask = double_int_to_tree (TREE_TYPE (rep),
+				  ~double_int::mask
+				  (TREE_INT_CST_LOW (size)).lshift (off));
+  gimple tems = gimple_build_assign_with_ops (BIT_AND_EXPR,
+					      masked, loadres, mask);
+  gsi_insert_before (gsi, tems, GSI_SAME_STMT);
+  /* Zero-extend the value to representative size.  */
+  tree tem2;
+  if (!TYPE_UNSIGNED (TREE_TYPE (field)))
+    {
+      tem2 = make_ssa_name (unsigned_type_for (TREE_TYPE (field)), NULL);
+      tems = gimple_build_assign_with_ops (NOP_EXPR, tem2,
+					   gimple_assign_rhs1 (stmt),
+					   NULL_TREE);
+      gsi_insert_before (gsi, tems, GSI_SAME_STMT);
+    }
+  else
+    tem2 = gimple_assign_rhs1 (stmt);
+  tree tem = make_ssa_name (TREE_TYPE (rep), NULL);
+  tems = gimple_build_assign_with_ops (NOP_EXPR, tem, tem2, NULL_TREE);
+  gsi_insert_before (gsi, tems, GSI_SAME_STMT);
+  /* Shift the value into place.  */
+  if (off != 0)
+    {
+      tem2 = make_ssa_name (TREE_TYPE (rep), NULL);
+      tems = gimple_build_assign_with_ops (LSHIFT_EXPR, tem2, tem,
+					   size_int (off));
+      gsi_insert_before (gsi, tems, GSI_SAME_STMT);
+    }
+  else
+    tem2 = tem;
+  /* Merge masked loaded value and value.  */
+  tree modres = make_ssa_name (TREE_TYPE (rep), NULL);
+  gimple mod = gimple_build_assign_with_ops (BIT_IOR_EXPR, modres,
+					     masked, tem2);
+  gsi_insert_before (gsi, mod, GSI_SAME_STMT);
+  /* Finally adjust the store.  */
+  gimple_assign_set_rhs1 (stmt, modres);
+  gimple_assign_set_lhs (stmt,
+			 build3 (COMPONENT_REF, TREE_TYPE (rep),
+				 TREE_OPERAND (ref, 0), rep, NULL_TREE));
+  update_stmt (stmt);
+}
+
+/* Connecting register with bit-field access sequence that defines value in
+   that register.  */
+struct bitfield_stmt_access_pair
+{
+  gimple stmt;
+  bfaccess *access;
+  bitfield_stmt_access_pair (gimple s, bfaccess *a):stmt (s), access (a) {};
+  /* hash_table support.  */
+  typedef bitfield_stmt_access_pair value_type;
+  typedef bitfield_stmt_access_pair compare_type;
+  static inline hashval_t hash (const bitfield_stmt_access_pair *);
+  static inline int equal (const bitfield_stmt_access_pair *,
+			   const bitfield_stmt_access_pair *);
+  static inline void remove (bitfield_stmt_access_pair *);
+};
+
+hashval_t bitfield_stmt_access_pair::hash (const bitfield_stmt_access_pair *a)
+{
+  return hashval_t (gimple_uid (a->stmt));
+}
+
+int bitfield_stmt_access_pair::equal (const bitfield_stmt_access_pair *a,
+				      const bitfield_stmt_access_pair *b)
+{
+  return a->stmt == b->stmt;
+}
+
+void bitfield_stmt_access_pair::remove (bitfield_stmt_access_pair *a)
+{
+  delete a;
+}
+
+/* Create new bit-field access structure and add it to given bitfield_accesses
+   htab.  */
+
+static struct bfaccess *
+create_and_insert_access (vec < struct bfaccess *>*bitfield_accesses,
+			  struct bfaccess *access)
+{
+  if (!access)
+    access = new bfaccess (NULL);
+  bitfield_accesses->safe_push (access);
+  return access;
+
+}
+
+static inline HOST_WIDE_INT
+get_bit_offset (tree decl)
+{
+  tree type = DECL_BIT_FIELD_TYPE (decl);
+  HOST_WIDE_INT bitpos_int;
+
+  /* Must be a field and a bit-field.  */
+  gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
+  /* Bit position and decl size should be integer constants that can be
+     represented in a signle HOST_WIDE_INT.  */
+  if (!tree_fits_uhwi_p (bit_position (decl))
+      || !tree_fits_uhwi_p (DECL_SIZE (decl)))
+    return -1;
+
+  bitpos_int = int_bit_position (decl);
+  return bitpos_int;
+}
+
+static bool
+add_stmt_access_pair (hash_table < bitfield_stmt_access_pair > &bf_stmnt_acc,
+		      bfaccess *access, gimple stmt)
+{
+  bitfield_stmt_access_pair p(stmt, access);
+  bitfield_stmt_access_pair  **slot = bf_stmnt_acc.find_slot (&p, INSERT);
+  if (!*slot)
+    {
+      *slot = new bitfield_stmt_access_pair (stmt, access);
+      return true;
+    }
+  return false;
+}
+
+/* Compare two bit-field access records.  */
+
+static int
+cmp_access (const void *p1, const void *p2)
+{
+  const struct bfaccess *a1 = *((const struct bfaccess **) p1);
+  const struct bfaccess *a2 = *((const struct bfaccess **) p2);
+
+  if (DECL_UID (a1->bitfield_representative) -
+      DECL_UID (a2->bitfield_representative))
+    return DECL_UID (a1->bitfield_representative) -
+      DECL_UID (a2->bitfield_representative);
+
+  if (!expressions_equal_p (a1->src_addr, a2->src_addr))
+    return a1 - a2;
+  if (!expressions_equal_p (a1->dst_addr, a2->dst_addr))
+    return a1 - a2;
+  if (a1->src_offset_words - a2->src_offset_words)
+    return a1->src_offset_words - a2->src_offset_words;
+  return a1->src_bit_offset - a2->src_bit_offset;
+}
+
+/* Returns size of combined bitfields.  Size cannot be larger than size
+   of largest directly accessible memory unit.  */
+
+static int
+get_merged_bit_field_size (bfaccess * access)
+{
+  bfaccess *tmp_access = access;
+  int size = 0;
+
+  while (tmp_access)
+    {
+      size += tmp_access->src_bit_size;
+      tmp_access = tmp_access->next;
+    }
+  return size;
+}
+
+/* Lower bitfield accesses to accesses of their
+   DECL_BIT_FIELD_REPRESENTATIVE.  */
+
+static void
+lower_bitfields (bool all)
+{
+  basic_block bb;
+
+  hash_table < bfaccess > bf;
+  bf.create (1);
+  hash_table < bitfield_stmt_access_pair > bf_stmnt_acc;
+  bf_stmnt_acc.create (1);
+
+  vec < struct bfaccess *>bitfield_accesses;
+  struct bfaccess *access;
+
+  FOR_EACH_BB_FN (bb, cfun)
+  {
+    bool any = false;
+    bf.empty ();
+    bf_stmnt_acc.empty ();
+    tree prev_representative = NULL_TREE;
+    bitfield_accesses.create (0);
+
+    /* We do two passes, the first one identifying interesting
+       bitfield accesses and the second one actually lowering them.  */
+    if (!all)
+      for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+	   !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  gimple stmt = gsi_stmt (gsi);
+
+	  if (!gimple_assign_single_p (stmt)
+	      || gimple_has_volatile_ops (stmt))
+	    continue;
+
+	  tree ref = gimple_assign_rhs1 (stmt);
+	  if (bitfield_access_p (ref, NULL))
+	    {
+	      bfaccess a (ref);
+	      bfaccess **slot = bf.find_slot (&a, INSERT);
+	      gimple use_stmt;
+	      use_operand_p use;
+	      tree op0 = TREE_OPERAND (ref, 0);
+	      tree op1 = TREE_OPERAND (ref, 1);
+
+	      if (TREE_CODE (DECL_CONTEXT (op1)) == UNION_TYPE
+		  || TREE_CODE (DECL_CONTEXT (op1)) == QUAL_UNION_TYPE)
+		continue;
+
+	      if (*slot)
+		(*slot)->r_count++;
+	      else
+		*slot = new bfaccess (a);
+
+	      if ((*slot)->r_count > 1)
+		any = true;
+
+	      if (single_imm_use (gimple_assign_lhs (stmt), &use, &use_stmt)
+		  && is_gimple_assign (use_stmt))
+		{
+		  tree uses_stmt_lhs = gimple_assign_lhs (use_stmt);
+		  if (bitfield_access_p (uses_stmt_lhs, NULL))
+		    {
+		      tree use_op0 = TREE_OPERAND (uses_stmt_lhs, 0);
+		      tree use_op1 = TREE_OPERAND (uses_stmt_lhs, 1);
+		      tree use_repr = DECL_BIT_FIELD_REPRESENTATIVE (use_op1);
+
+		      if (prev_representative
+			  && (prev_representative != use_repr))
+			{
+			  /* If previous access has different
+			     representative then barrier is needed
+			     between it and new access.  */
+			  access = create_and_insert_access
+			    (&bitfield_accesses, NULL);
+			  access->is_barrier = true;
+			}
+		      prev_representative = use_repr;
+		      /* Create new bit-field access structure.  */
+		      access = create_and_insert_access
+			(&bitfield_accesses, NULL);
+		      /* Collect access data - load instruction.  */
+		      access->src_bit_size = tree_to_uhwi (DECL_SIZE (op1));
+		      access->src_bit_offset = get_bit_offset (op1);
+		      access->src_offset_words =
+			field_byte_offset (op1) / UNITS_PER_WORD;
+		      access->src_field_offset =
+			tree_to_uhwi (DECL_FIELD_OFFSET (op1));
+		      access->src_addr = op0;
+		      access->load_stmt = gsi_stmt (gsi);
+		      /* Collect access data - store instruction.  */
+		      access->dst_bit_size =
+			tree_to_uhwi (DECL_SIZE (use_op1));
+		      access->dst_bit_offset = get_bit_offset (use_op1);
+		      access->dst_offset_words =
+			field_byte_offset (use_op1) / UNITS_PER_WORD;
+		      access->dst_addr = use_op0;
+		      access->store_stmt = use_stmt;
+		      add_stmt_access_pair (bf_stmnt_acc, access, stmt);
+		      add_stmt_access_pair (bf_stmnt_acc, access, use_stmt);
+		      access->bitfield_representative = use_repr;
+		    }
+		}
+	    }
+
+	  ref = gimple_assign_lhs (stmt);
+	  if (bitfield_access_p (ref, NULL))
+	    {
+	      bfaccess a (ref);
+	      bfaccess **slot = bf.find_slot (&a, INSERT);
+	      if (*slot)
+		(*slot)->w_count++;
+	      else
+		*slot = new bfaccess (a);
+	      if ((*slot)->w_count > 1)
+		any = true;
+	    }
+	  /* Insert barrier for merging if statement is function call or memory
+	     access.  */
+	  bitfield_stmt_access_pair asdata (stmt, NULL);
+	  if (!bf_stmnt_acc.find (&asdata)
+	      && ((gimple_code (stmt) == GIMPLE_CALL)
+		 || (gimple_has_mem_ops (stmt))))
+	    {
+	      /* Create new bit-field access structure.  */
+	      access = create_and_insert_access (&bitfield_accesses, NULL);
+	      /* Mark it as barrier.  */
+	      access->is_barrier = true;
+	    }
+	}
+
+    if (!all && !any)
+      continue;
+
+    /* If there are no at least two accesses go to the next basic block.  */
+    if (bitfield_accesses.length () <= 1)
+      {
+	bitfield_accesses.release ();
+	continue;
+      }
+    vec < struct bfaccess *>bitfield_accesses_merge = vNULL;
+    /* Find bit-field accesses that can be merged.  */
+    for (int ix = 0; bitfield_accesses.iterate (ix, &access); ix++)
+      {
+	struct bfaccess *head_access;
+	struct bfaccess *mrg_access;
+	struct bfaccess *prev_access;
+
+	if (!bitfield_accesses_merge.exists ())
+	  bitfield_accesses_merge.create (0);
+
+	if (!access->is_barrier)
+	  bitfield_accesses_merge.safe_push (access);
+
+	if (!access->is_barrier
+	    && !(access == bitfield_accesses.last ()
+		 && !bitfield_accesses_merge.is_empty ()))
+	  continue;
+
+	bitfield_accesses_merge.qsort (cmp_access);
+	head_access = prev_access = NULL;
+	int iy;
+	for (iy = 0; bitfield_accesses_merge.iterate (iy, &mrg_access); iy++)
+	  {
+	    if (head_access
+		&& expressions_equal_p (head_access->src_addr,
+					mrg_access->src_addr)
+		&& expressions_equal_p (head_access->dst_addr,
+					mrg_access->dst_addr)
+		&& prev_access->src_offset_words
+		== mrg_access->src_offset_words
+		&& prev_access->dst_offset_words
+		== mrg_access->dst_offset_words
+		&& prev_access->src_bit_offset + prev_access->src_bit_size
+		== mrg_access->src_bit_offset
+		&& prev_access->dst_bit_offset + prev_access->dst_bit_size
+		== mrg_access->dst_bit_offset
+		&& prev_access->bitfield_representative
+		== mrg_access->bitfield_representative)
+	      {
+		/* Merge conditions are satisfied - merge accesses.  */
+		mrg_access->merged = true;
+		prev_access->next = mrg_access;
+		head_access->modified = true;
+		prev_access = mrg_access;
+		mrg_access->head_access = head_access;
+	      }
+	    else
+	      head_access = prev_access = mrg_access;
+	  }
+	bitfield_accesses_merge.release ();
+	bitfield_accesses_merge = vNULL;
+      }
+
+    for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+	 !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+	gimple stmt = gsi_stmt (gsi);
+	if (!gimple_assign_single_p (stmt) || gimple_has_volatile_ops (stmt))
+	  continue;
+
+	tree ref;
+	unsigned HOST_WIDE_INT off;
+	tree size;
+
+	/* Lower a bitfield read.  */
+	ref = gimple_assign_rhs1 (stmt);
+	if (bitfield_access_p (ref, &off))
+	  {
+	    bfaccess a (ref);
+	    bfaccess *aa = NULL;
+	    bitfield_stmt_access_pair st_acc (stmt, NULL);
+	    bitfield_stmt_access_pair *p_st_acc;
+	    p_st_acc = bf_stmnt_acc.find (&st_acc);
+	    if (p_st_acc)
+	      aa = p_st_acc->access;
+	    if (!aa)
+	      aa = bf.find (&a);
+
+	    if (aa->merged || aa->modified)
+	      size =
+		build_int_cst (unsigned_type_node,
+			       get_merged_bit_field_size (aa->
+							  head_access ? aa->
+							  head_access : aa));
+	    else
+	      size = DECL_SIZE (TREE_OPERAND (ref, 1));
+	    if (aa->merged)
+	      off = aa->head_access->src_bit_offset;
+
+	    if (aa->merged || aa->modified)
+	      {
+		tree tmp_ssa;
+		tree itype = make_node (INTEGER_TYPE);
+		TYPE_PRECISION (itype) = TREE_INT_CST_LOW (size);
+		fixup_unsigned_type (itype);
+		lower_bitfield_read (&gsi, off, size, itype);
+		tmp_ssa =
+		make_ssa_name (create_tmp_var (itype, NULL), NULL);
+		gimple_assign_set_lhs (aa->load_stmt, tmp_ssa);
+		update_stmt (aa->load_stmt);
+		gimple_assign_set_rhs1 (aa->store_stmt, tmp_ssa);
+	      }
+	    else if (all || (aa->r_count > 1))
+	      lower_bitfield_read (&gsi, off, size, NULL);
+	  }
+	/* Lower a bitfield write to a read-modify-write cycle.  */
+	ref = gimple_assign_lhs (stmt);
+	if (bitfield_access_p (ref, &off))
+	  {
+	    bfaccess a (ref);
+	    bfaccess *aa = NULL;
+	    bitfield_stmt_access_pair st_acc (stmt, NULL);
+	    bitfield_stmt_access_pair *p_st_acc;
+	    p_st_acc = bf_stmnt_acc.find (&st_acc);
+	    if (p_st_acc)
+	      aa = p_st_acc->access;
+	    if (!aa)
+	      aa = bf.find (&a);
+
+	    if (aa->merged || aa->modified)
+	      size =
+		build_int_cst (unsigned_type_node,
+			       get_merged_bit_field_size (aa->
+							  head_access ? aa->
+							  head_access : aa));
+	    else
+	      size = DECL_SIZE (TREE_OPERAND (ref, 1));
+	    if (aa->merged)
+	      off = aa->head_access->dst_bit_offset;
+
+	    if (all || (aa->w_count > 1) || aa->merged || aa->modified)
+	      lower_bitfield_write (&gsi, off, size);
+	  }
+      }
+  }
+
+  bf.dispose ();
+  bf_stmnt_acc.dispose ();
+}
+
 /* Perform early intraprocedural SRA.  */
 static unsigned int
 early_intra_sra (void)
 {
+
+  if (flag_tree_bitfield_merge)
+    lower_bitfields (false);
   sra_mode = SRA_MODE_EARLY_INTRA;
   return perform_intra_sra ();
 }
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index f7ec8b6..cde6ce6 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -4193,29 +4193,6 @@  get_next_value_id (void)
   return next_value_id++;
 }
 
-
-/* Compare two expressions E1 and E2 and return true if they are equal.  */
-
-bool
-expressions_equal_p (tree e1, tree e2)
-{
-  /* The obvious case.  */
-  if (e1 == e2)
-    return true;
-
-  /* If only one of them is null, they cannot be equal.  */
-  if (!e1 || !e2)
-    return false;
-
-  /* Now perform the actual comparison.  */
-  if (TREE_CODE (e1) == TREE_CODE (e2)
-      && operand_equal_p (e1, e2, OEP_PURE_SAME))
-    return true;
-
-  return false;
-}
-
-
 /* Return true if the nary operation NARY may trap.  This is a copy
    of stmt_could_throw_1_p adjusted to the SCCVN IL.  */
 
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index f52783a..0aa5537 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -21,10 +21,6 @@ 
 #ifndef TREE_SSA_SCCVN_H
 #define TREE_SSA_SCCVN_H
 
-/* In tree-ssa-sccvn.c  */
-bool expressions_equal_p (tree, tree);
-
-
 /* TOP of the VN lattice.  */
 extern tree VN_TOP;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index d102d07..78355cc 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12369,4 +12369,44 @@  get_base_address (tree t)
   return t;
 }
 
+/* Compare two expressions E1 and E2 and return true if they are equal.  */
+
+bool
+expressions_equal_p (tree e1, tree e2)
+{
+  /* The obvious case.  */
+  if (e1 == e2)
+    return true;
+
+  /* If only one of them is null, they cannot be equal.  */
+  if (!e1 || !e2)
+    return false;
+
+  /* Now perform the actual comparison.  */
+  if (TREE_CODE (e1) == TREE_CODE (e2)
+      && operand_equal_p (e1, e2, OEP_PURE_SAME))
+    return true;
+
+  return false;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+   node, return the size in bits for the type if it is a constant, or else
+   return the alignment for the type if the type's size is not constant, or
+   else return BITS_PER_WORD if the type actually turns out to be an
+   ERROR_MARK node.  */
+
+unsigned HOST_WIDE_INT
+simple_type_size_in_bits (const_tree type)
+{
+  if (TREE_CODE (type) == ERROR_MARK)
+    return BITS_PER_WORD;
+  else if (TYPE_SIZE (type) == NULL_TREE)
+    return 0;
+  else if (tree_fits_uhwi_p (TYPE_SIZE (type)))
+    return tree_to_uhwi (TYPE_SIZE (type));
+  else
+    return TYPE_ALIGN (type);
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index 0dc8d0d..4a5b930 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3984,6 +3984,7 @@  extern tree substitute_placeholder_in_expr (tree, tree);
   ((EXP) == 0 || TREE_CONSTANT (EXP) ? (EXP)	\
    : substitute_placeholder_in_expr (EXP, OBJ))
 
+extern unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree type);
 
 /* stabilize_reference (EXP) returns a reference equivalent to EXP
    but it can be used multiple times
@@ -4100,6 +4101,11 @@  inlined_function_outer_scope_p (const_tree block)
        (TREE = function_args_iter_cond (&(ITER))) != NULL_TREE;		\
        function_args_iter_next (&(ITER)))
 
+
+/* In dwarf2out.c.  */
+HOST_WIDE_INT
+field_byte_offset (const_tree decl);
+
 /* In tree.c */
 extern unsigned crc32_string (unsigned, const char *);
 extern unsigned crc32_byte (unsigned, char);
@@ -4244,6 +4250,7 @@  extern tree obj_type_ref_class (tree ref);
 extern bool types_same_for_odr (tree type1, tree type2);
 extern bool contains_bitfld_component_ref_p (const_tree);
 extern bool type_in_anonymous_namespace_p (tree);
+extern bool expressions_equal_p (tree e1, tree e2);
 extern bool block_may_fallthru (const_tree);
 extern void using_eh_for_cleanups (void);
 extern bool using_eh_for_cleanups_p (void);