On Wed, Jul 17, 2013 at 1:38 PM, Zoran Jovanovic
<zoran.jovano...@imgtec.com> wrote:
> 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.


This patch looks like it will fix
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45274 .

Thanks,
Andrew Pinski

>
> Changelog -
>
> gcc/ChangeLog:
> 2013-07-17 Zoran Jovanovic (zoran.jovano...@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
>

Reply via email to