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] Add a new option "-ftree-bitfield-merge" (patch / doc inside)


Hello,
This patch adds new optimization pass that combines several adjacent bit field accesses that copy values from one memory location to another into single bit field access.

Example:

Original code:
  <unnamed-unsigned:3> D.1351;
  <unnamed-unsigned:9> D.1350;
  <unnamed-unsigned:7> D.1349;
  D.1349_2 = p1_1(D)->f1;
  p2_3(D)->f1 = D.1349_2;
  D.1350_4 = p1_1(D)->f2;
  p2_3(D)->f2 = D.1350_4;
  D.1351_5 = p1_1(D)->f3;
  p2_3(D)->f3 = D.1351_5;

Optimized code:
  <unnamed-unsigned:19> D.1358;
  D.1358_10 = BIT_FIELD_REF <*p1_1(D), 19, 13>;
  BIT_FIELD_REF <*p2_3(D), 19, 13> = D.1358_10;

Algorithm works on basic block level and consists of following 3 major steps:
1. Go trough 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. Modify trees accordingly.

New command line option "-ftree-bitfield-merge" is introduced.

Tested - passed gcc regression tests.

Changelog -

gcc/ChangeLog:
2013-07-17 Zoran Jovanovic (zoran.jovanovic@imgtec.com)
  * Makefile.in : Added tree-ssa-bitfield-merge.o to OBJS.
  * common.opt (ftree-bitfield-merge): New option.
  * doc/invoke.texi: Added reference to "-ftree-bitfield-merge".
  * dwarf2out.c (field_type): static removed from declaration.
  (simple_type_size_in_bits): static removed from declaration.
  (field_byte_offset): static removed from declaration.
  (field_type): static inline removed from declaration.
  * passes.c (init_optimization_passes): pass_bitfield_merge pass added.
  * testsuite/gcc.dg/tree-ssa/bitfldmrg.c: New test.
  * timevar.def : Added TV_TREE_BITFIELD_MERGE.
  * tree-pass.h : Added pass_bitfield_merge declaration.
  * tree-ssa-bitfield-merge.c : New file.

Patch -

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index d5121f3..5cdd6eb 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1417,6 +1417,7 @@ OBJS = \
 	tree-ssa-dom.o \
 	tree-ssa-dse.o \
 	tree-ssa-forwprop.o \
+	tree-ssa-bitfield-merge.o \
 	tree-ssa-ifcombine.o \
 	tree-ssa-live.o \
 	tree-ssa-loop-ch.o \
@@ -2312,6 +2313,11 @@ tree-ssa-forwprop.o : tree-ssa-forwprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TREE_FLOW_H) $(TREE_PASS_H) $(DIAGNOSTIC_H) \
    langhooks.h $(FLAGS_H) $(GIMPLE_H) $(GIMPLE_PRETTY_PRINT_H) $(EXPR_H) \
    $(OPTABS_H) tree-ssa-propagate.h
+tree-ssa-bitfield-merge.o : tree-ssa-forwprop.c $(CONFIG_H) $(SYSTEM_H) \
+   coretypes.h $(TM_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
+   $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
+   langhooks.h $(FLAGS_H) $(GIMPLE_H) tree-pretty-print.h \
+   gimple-pretty-print.h $(EXPR_H)
 tree-ssa-phiprop.o : tree-ssa-phiprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
    $(TREE_FLOW_H) $(TREE_PASS_H) $(DIAGNOSTIC_H) \
@@ -3803,6 +3809,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/ipa-inline.h \
   $(srcdir)/asan.c \
   $(srcdir)/tsan.c \
+  $(srcdir)/tree-ssa-bitfield-merge.c \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/common.opt b/gcc/common.opt
index 4c7933e..e0dbc37 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2088,6 +2088,10 @@ ftree-forwprop
 Common Report Var(flag_tree_forwprop) Init(1) Optimization
 Enable forward propagation on trees
 
+ftree-bitfield-merge
+Common Report Var(flag_tree_bitfield_merge) Init(0) Optimization
+Enable bit field merge on trees
+
 ftree-fre
 Common Report Var(flag_tree_fre) Optimization
 Enable Full Redundancy Elimination (FRE) on trees
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index dd82880..7b671aa 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -409,7 +409,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
+-ftree-bitfield-merge -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
@@ -7582,6 +7582,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 -ftree-bitfield-merge
+@opindex ftree-bitfield-merge
+Combines several adjacent bit field accesses that copy values
+from one memory location to another into 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 f42ad66..a08eede 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3100,11 +3100,11 @@ static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
 static dw_loc_list_ref loc_list_from_tree (tree, int);
 static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
-static tree field_type (const_tree);
+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);
+unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
+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);
@@ -10061,7 +10061,7 @@ is_base_type (tree type)
    else return BITS_PER_WORD if the type actually turns out to be an
    ERROR_MARK node.  */
 
-static inline unsigned HOST_WIDE_INT
+unsigned HOST_WIDE_INT
 simple_type_size_in_bits (const_tree type)
 {
   if (TREE_CODE (type) == ERROR_MARK)
@@ -14375,7 +14375,7 @@ ceiling (HOST_WIDE_INT value, unsigned int boundary)
    `integer_type_node' if the given node turns out to be an
    ERROR_MARK node.  */
 
-static inline tree
+tree
 field_type (const_tree decl)
 {
   tree type;
@@ -14426,7 +14426,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/passes.c b/gcc/passes.c
index c8b03ee..3149adc 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1325,6 +1325,7 @@ init_optimization_passes (void)
 	  NEXT_PASS (pass_remove_cgraph_callee_edges);
 	  NEXT_PASS (pass_rename_ssa_copies);
 	  NEXT_PASS (pass_ccp);
+	  NEXT_PASS (pass_bitfield_merge);
 	  /* After CCP we rewrite no longer addressed locals into SSA
 	     form if possible.  */
 	  NEXT_PASS (pass_forwprop);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitfldmrg.c b/gcc/testsuite/gcc.dg/tree-ssa/bitfldmrg.c
new file mode 100644
index 0000000..9be6bc9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bitfldmrg.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-bitfield-merge -fdump-tree-bitfieldmerge" }  */
+
+struct S
+{
+  unsigned f1:7;
+  unsigned f2:9;
+  unsigned f3:3;
+  unsigned f4:5;
+  unsigned f5:1;
+  unsigned f6:2;
+};
+
+unsigned
+foo (struct S *p1, struct S *p2, int *ptr)
+{
+  p2->f1 = p1->f1;
+  p2->f2 = p1->f2;
+  p2->f3 = p1->f3;
+  *ptr = 7;
+  p2->f4 = p1->f4;
+  p2->f5 = p1->f5;
+  p2->f6 = p1->f6;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump "19" "bitfieldmerge" } } */
+/* { dg-final { scan-tree-dump "8" "bitfieldmerge"} } */
+/* { dg-final { cleanup-tree-dump "bitfieldmerge" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 44f0eac..d9b1c23 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_FRE		     , "tree FRE")
 DEFTIMEVAR (TV_TREE_SINK             , "tree code sinking")
 DEFTIMEVAR (TV_TREE_PHIOPT	     , "tree linearize phis")
 DEFTIMEVAR (TV_TREE_FORWPROP	     , "tree forward propagate")
+DEFTIMEVAR (TV_TREE_BITFIELD_MERGE   , "tree bitfield merge")
 DEFTIMEVAR (TV_TREE_PHIPROP	     , "tree phiprop")
 DEFTIMEVAR (TV_TREE_DCE		     , "tree conservative DCE")
 DEFTIMEVAR (TV_TREE_CD_DCE	     , "tree aggressive DCE")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index b8c59a7..59ca028 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -337,6 +337,7 @@ extern struct gimple_opt_pass pass_warn_function_noreturn;
 extern struct gimple_opt_pass pass_cselim;
 extern struct gimple_opt_pass pass_phiopt;
 extern struct gimple_opt_pass pass_forwprop;
+extern struct gimple_opt_pass pass_bitfield_merge;
 extern struct gimple_opt_pass pass_phiprop;
 extern struct gimple_opt_pass pass_tree_ifcombine;
 extern struct gimple_opt_pass pass_dse;
diff --git a/gcc/tree-ssa-bitfield-merge.c b/gcc/tree-ssa-bitfield-merge.c
new file mode 100755
index 0000000..71f41b3
--- /dev/null
+++ b/gcc/tree-ssa-bitfield-merge.c
@@ -0,0 +1,503 @@
+/* Forward propagation of expressions for single use variables.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "timevar.h"
+#include "gimple-pretty-print.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "tree-dump.h"
+#include "langhooks.h"
+#include "flags.h"
+#include "gimple.h"
+#include "expr.h"
+#include "ggc.h"
+
+tree
+field_type (const_tree decl);
+
+bool
+expressions_equal_p (tree e1, tree e2);
+
+HOST_WIDE_INT
+field_byte_offset (const_tree decl);
+
+unsigned HOST_WIDE_INT
+simple_type_size_in_bits (const_tree type);
+
+/* This pass combines several adjacent bit field accesses that copy values
+   from one memory location to another into single bit field access.  */
+
+/* Data for single bit field read/write sequence.  */
+struct GTY (()) bitfield_access_d {
+  gimple load_stmt;		  /* Bit field load statement.  */
+  gimple store_stmt;		  /* Bit field store statement.  */
+  unsigned src_offset_bytes;	  /* Bit field offset at src in bytes.  */
+  unsigned src_bit_offset;	  /* Bit field offset inside source word.  */
+  unsigned src_bit_size;	  /* Size of bit field in source word.  */
+  unsigned dst_offset_bytes;	  /* Bit field offset at dst in bytes.  */
+  unsigned dst_bit_offset;	  /* Bit field offset inside destination
+				     word.  */
+  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 bitfield size is modified.  */
+  bool is_barrier;		  /* True if access is barrier (call or mem
+				     access).  */
+  struct bitfield_access_d *next; /* Access with which this one is merged.  */
+};
+
+typedef struct bitfield_access_d bitfield_access_o;
+typedef struct bitfield_access_d *bitfield_access;
+
+/* Connecting register with bit field access sequence that defines value in
+   that register.  */
+struct GTY (()) bitfield_stmt_access_pair_d
+{
+  gimple stmt;
+  bitfield_access access;
+};
+
+typedef struct bitfield_stmt_access_pair_d bitfield_stmt_access_pair_o;
+typedef struct bitfield_stmt_access_pair_d *bitfield_stmt_access_pair;
+
+static GTY ((param_is (struct bitfield_stmt_access_pair_d)))
+  htab_t bitfield_stmt_access_htab;
+
+/* Hash table callbacks for bitfield_stmt_access_htab.  */
+
+static hashval_t
+bitfield_stmt_access_pair_htab_hash (const void *p)
+{
+  const struct bitfield_stmt_access_pair_d *entry =
+    (const struct bitfield_stmt_access_pair_d *)p;
+  return (hashval_t) (uintptr_t) entry->stmt;
+}
+
+static int
+bitfield_stmt_access_pair_htab_eq (const void *p1, const void *p2)
+{
+  const struct bitfield_stmt_access_pair_d *entry1 =
+    (const struct bitfield_stmt_access_pair_d *)p1;
+  const struct bitfield_stmt_access_pair_d *entry2 =
+    (const struct bitfield_stmt_access_pair_d *)p2;
+  return entry1->stmt == entry2->stmt;
+}
+
+
+static bool cfg_changed;
+
+/* Compare two bit field access records.  */
+
+static int
+cmp_access (const void *p1, const void *p2)
+{
+  const bitfield_access a1 = (*(const bitfield_access*)p1);
+  const bitfield_access a2 = (*(const bitfield_access*)p2);
+
+  if (!expressions_equal_p (a1->src_addr, a1->src_addr))
+    return a1 - a2;
+
+  if (!expressions_equal_p (a1->dst_addr, a1->dst_addr))
+    return a1 - a2;
+
+  return a1->src_bit_offset - a2->src_bit_offset;
+}
+
+/* Create new bit field access structure and add it to given bitfield_accesses
+   htab.  */
+static bitfield_access
+create_and_insert_access (vec<bitfield_access>
+		       *bitfield_accesses)
+{
+  bitfield_access access = ggc_alloc_bitfield_access_d ();
+  memset (access, 0, sizeof (struct bitfield_access_d));
+  bitfield_accesses->safe_push (access);
+  return access;
+}
+
+/* Slightly modified add_bit_offset_attribute from dwarf2out.c.  */
+static inline HOST_WIDE_INT
+get_bit_offset (tree decl)
+{
+  HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
+  tree type = DECL_BIT_FIELD_TYPE (decl);
+  HOST_WIDE_INT bitpos_int;
+  HOST_WIDE_INT highest_order_object_bit_offset;
+  HOST_WIDE_INT highest_order_field_bit_offset;
+  HOST_WIDE_INT bit_offset;
+
+  /* Must be a field and a bit field.  */
+  gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
+  if (! host_integerp (bit_position (decl), 0)
+      || ! host_integerp (DECL_SIZE (decl), 1))
+    return -1;
+
+  bitpos_int = int_bit_position (decl);
+
+  /* Note that the bit offset is always the distance (in bits) from the
+     highest-order bit of the "containing object" to the highest-order bit of
+     the bit-field itself.  Since the "high-order end" of any object or field
+     is different on big-endian and little-endian machines, the computation
+     below must take account of these differences.  */
+  highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
+  highest_order_field_bit_offset = bitpos_int;
+
+  if (! BYTES_BIG_ENDIAN)
+    {
+      highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 0);
+      highest_order_object_bit_offset += simple_type_size_in_bits (type);
+    }
+
+  bit_offset
+    = (! BYTES_BIG_ENDIAN
+       ? highest_order_object_bit_offset - highest_order_field_bit_offset
+       : highest_order_field_bit_offset - highest_order_object_bit_offset);
+
+  return bit_offset;
+}
+
+/* Slightly modified add_byte_size_attribute from dwarf2out.c.  */
+static inline HOST_WIDE_INT
+get_byte_size (tree tree_node)
+{
+  unsigned size;
+
+  switch (TREE_CODE (tree_node))
+    {
+    case ERROR_MARK:
+      size = 0;
+      break;
+    case ENUMERAL_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      size = int_size_in_bytes (tree_node);
+      break;
+    case FIELD_DECL:
+      /* For a data member of a struct or union, the DW_AT_byte_size is
+	 generally given as the number of bytes normally allocated for an
+	 object of the *declared* type of the member itself.  This is true
+	 even for bit-fields.  */
+      size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  return size;
+}
+
+/* Returns size of combined bitfields.  */
+static int
+get_merged_bit_field_size (bitfield_access access)
+{
+  bitfield_access tmp_access = access;
+  int size = 0;
+
+  while (tmp_access)
+  {
+    size += tmp_access->src_bit_size;
+    tmp_access = tmp_access->next;
+  }
+  return size;
+}
+
+/* Adds new pair consisting of statement and bit field access structure that
+   contains it.  */
+static bool add_stmt_access_pair (bitfield_access access, gimple stmt)
+{
+  bitfield_stmt_access_pair new_pair;
+  void **slot;
+  new_pair = ggc_alloc_bitfield_stmt_access_pair_o ();
+  new_pair->stmt = stmt;
+  new_pair->access = access;
+  slot = htab_find_slot (bitfield_stmt_access_htab, new_pair, INSERT);
+  if (*slot == HTAB_EMPTY_ENTRY)
+    {
+      *slot = new_pair;
+      return true;
+    }
+  return false;
+}
+
+/* Main entry point for the bit field merge optimization.  */
+static unsigned int
+ssa_bitfield_merge (void)
+{
+  basic_block bb;
+  unsigned int todoflags = 0;
+  vec<bitfield_access> bitfield_accesses;
+  int ix, iy;
+  bitfield_access access;
+
+  cfg_changed = false;
+
+  FOR_EACH_BB (bb)
+    {
+      gimple_stmt_iterator gsi;
+      vec<bitfield_access> bitfield_accesses_merge = vNULL;
+      bitfield_accesses.create (0);
+
+      bitfield_stmt_access_htab
+	= htab_create_ggc (128,
+			 bitfield_stmt_access_pair_htab_hash,
+			 bitfield_stmt_access_pair_htab_eq,
+			 NULL);
+
+      /* Identify all bitfield copy sequences in the basic-block.  */
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+	{
+	  gimple stmt = gsi_stmt (gsi);
+	  tree lhs, rhs;
+	  void **slot;
+	  struct bitfield_stmt_access_pair_d asdata;
+
+	  if (!is_gimple_assign (stmt))
+	    {
+	      gsi_next (&gsi);
+	      continue;
+	    }
+
+	  lhs = gimple_assign_lhs (stmt);
+	  rhs = gimple_assign_rhs1 (stmt);
+
+	  if (TREE_CODE (rhs) == COMPONENT_REF)
+	    {
+	      use_operand_p use;
+	      gimple use_stmt;
+	      tree op0 = TREE_OPERAND (rhs, 0);
+	      tree op1 = TREE_OPERAND (rhs, 1);
+
+	      if (TREE_CODE (op1) == FIELD_DECL && DECL_BIT_FIELD_TYPE (op1))
+		{
+		  if (single_imm_use (lhs, &use, &use_stmt)
+		       && is_gimple_assign (use_stmt))
+		    {
+		      tree use_lhs = gimple_assign_lhs (use_stmt);
+		      if (TREE_CODE (use_lhs) == COMPONENT_REF)
+			{
+			  tree use_op0 = TREE_OPERAND (use_lhs, 0);
+			  tree use_op1 = TREE_OPERAND (use_lhs, 1);
+			  if (TREE_CODE (use_op1) == FIELD_DECL
+			      && DECL_BIT_FIELD_TYPE (use_op1))
+			    {
+			      /* Create new bit field access structure.  */
+			      access = create_and_insert_access
+					 (&bitfield_accesses);
+			      /* Collect access data - load instruction.  */
+			      access->src_bit_size = tree_low_cst
+						      (DECL_SIZE (op1), 1);
+			      access->src_bit_offset = get_bit_offset (op1);
+			      access->src_offset_bytes = get_byte_size (op1);
+			      access->src_addr = op0;
+			      access->load_stmt = gsi_stmt (gsi);
+			      /* Collect access data - store instruction.  */
+			      access->dst_bit_size = tree_low_cst (DECL_SIZE
+								    (use_op1),
+								   1);
+			      access->dst_bit_offset = get_bit_offset
+							 (use_op1);
+			      access->dst_offset_bytes = get_byte_size
+							   (use_op1);
+			      access->dst_addr = use_op0;
+			      access->store_stmt = use_stmt;
+			      add_stmt_access_pair (access, stmt);
+			      add_stmt_access_pair (access, use_stmt);
+			    }
+			}
+		    }
+		}
+	    }
+
+	  /* Insert barrier for merging if statement is function call or memory
+	     access.  */
+	  asdata.stmt = stmt;
+	  slot = htab_find_slot (bitfield_stmt_access_htab, &asdata,
+				 NO_INSERT);
+	  if (!slot && ((gimple_code (stmt) == GIMPLE_CALL)
+	      || (gimple_has_mem_ops (stmt))))
+	    {
+	      /* Create new bit field access structure.  */
+	      access = create_and_insert_access (&bitfield_accesses);
+	      /* Mark it as barrier.  */
+	      access->is_barrier = true;
+	    }
+
+	  gsi_next (&gsi);
+	}
+
+      /* If there are no at least two accesses go to the next basic block.  */
+      if (bitfield_accesses.length () <= 1)
+	{
+	  bitfield_accesses.release ();
+	  continue;
+	}
+
+      /* Find bitfield accesses that can be merged.  */
+      for (ix = 0; bitfield_accesses.iterate (ix, &access); ix++)
+	{
+	  bitfield_access head_access;
+	  bitfield_access mrg_access;
+	  bitfield_access prev_access;
+
+	  if (!bitfield_accesses_merge.exists ())
+	    bitfield_accesses_merge.create (0);
+
+	  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 = NULL;
+	  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_bytes
+		     == prev_access->src_offset_bytes
+		  && prev_access->dst_offset_bytes
+		     == prev_access->dst_offset_bytes
+		  && 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)
+		{
+		  /* Merge conditions are satisfied - merge accesses.  */
+		  mrg_access->merged = true;
+		  prev_access->next = mrg_access;
+		  head_access->modified = true;
+		  prev_access = mrg_access;
+		}
+	      else
+		head_access = prev_access = mrg_access;
+	    }
+	  bitfield_accesses_merge.release ();
+	  bitfield_accesses_merge = vNULL;
+	}
+
+      /* Modify generated code.  */
+      for (ix = 0; bitfield_accesses.iterate (ix, &access); ix++)
+	{
+	  if (access->merged)
+	    {
+	      /* Access merged - remove instructions.  */
+	      gimple_stmt_iterator tmp_gsi;
+	      tmp_gsi = gsi_for_stmt (access->load_stmt);
+	      gsi_remove (&tmp_gsi, true);
+	      tmp_gsi = gsi_for_stmt (access->store_stmt);
+	      gsi_remove (&tmp_gsi, true);
+	    }
+	  else if (access->modified)
+	    {
+	      /* Access modified - modify generated code.  */
+	      gimple_stmt_iterator tmp_gsi;
+	      tree tmp_ssa;
+	      tree itype = make_node (INTEGER_TYPE);
+	      tree new_rhs;
+	      tree new_lhs;
+	      gimple new_stmt;
+
+	      /* Bitfield size changed - modify load statement.  */
+	      access->src_bit_size = get_merged_bit_field_size (access);
+	      TYPE_PRECISION (itype) = access->src_bit_size;
+	      fixup_unsigned_type (itype);
+	      tmp_ssa = make_ssa_name (create_tmp_var (itype, NULL), NULL);
+	      new_rhs = build3 (BIT_FIELD_REF, itype, access->src_addr,
+				build_int_cst (unsigned_type_node,
+					       access->src_bit_size),
+				build_int_cst (unsigned_type_node,
+					       access->src_bit_offset));
+
+	      tmp_gsi = gsi_for_stmt (access->load_stmt);
+	      new_stmt = gimple_build_assign (tmp_ssa, new_rhs);
+	      gsi_insert_after (&tmp_gsi, new_stmt, GSI_SAME_STMT);
+	      SSA_NAME_DEF_STMT (tmp_ssa) = new_stmt;
+	      gsi_remove (&tmp_gsi, true);
+
+	      /* Bitfield size changed - modify store statement.  */
+	      new_lhs = build3 (BIT_FIELD_REF, itype, access->dst_addr,
+				build_int_cst (unsigned_type_node,
+					       access->src_bit_size),
+				build_int_cst (unsigned_type_node,
+					       access->dst_bit_offset));
+
+	      tmp_gsi = gsi_for_stmt (access->store_stmt);
+	      new_stmt = gimple_build_assign (new_lhs, tmp_ssa);
+	      gsi_insert_after (&tmp_gsi, new_stmt, GSI_SAME_STMT);
+	      gsi_remove (&tmp_gsi, true);
+
+	      cfg_changed = true;
+	    }
+	}
+      /* Empty or delete data structures used for basic block.  */
+      htab_empty (bitfield_stmt_access_htab);
+      bitfield_accesses.release ();
+    }
+
+  if (cfg_changed)
+    todoflags |= TODO_cleanup_cfg;
+
+  return todoflags;
+}
+
+static bool
+gate_bitfield_merge (void)
+{
+  return flag_tree_bitfield_merge;
+}
+
+struct gimple_opt_pass pass_bitfield_merge =
+{
+ {
+  GIMPLE_PASS,
+  "bitfieldmerge",		/* name */
+  OPTGROUP_NONE,                /* optinfo_flags */
+  gate_bitfield_merge,		/* gate */
+  ssa_bitfield_merge,		/* execute */
+  NULL,				/* sub */
+  NULL,				/* next */
+  0,				/* static_pass_number */
+  TV_TREE_BITFIELD_MERGE,	/* tv_id */
+  PROP_cfg | PROP_ssa,		/* properties_required */
+  0,				/* properties_provided */
+  0,				/* properties_destroyed */
+  0,				/* todo_flags_start */
+  TODO_update_ssa
+  | TODO_verify_ssa		/* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-ssa-bitfield-merge.h"


Regards,
Zoran Jovanovic


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