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 >