gimple-ssa-store-merging.c (struct merged_store_group): Move up bit_insertion field and declare can_be_merged_into method.

* gimple-ssa-store-merging.c (struct merged_store_group): Move up
	bit_insertion field and declare can_be_merged_into method.
	(merged_store_group::can_be_merged_into): New method.
	(imm_store_chain_info::coalesce_immediate): Call it to decide whether
	consecutive non-overlapping stores can be merged.  Turn MEM_REF stores
	into BIT_INSERT_EXPR stores if the group contains a non-MEM_REF store.

From-SVN: r261173
This commit is contained in:
Eric Botcazou 2018-06-04 22:12:51 +00:00 committed by Eric Botcazou
parent d552d8190d
commit 7f5a398246
6 changed files with 146 additions and 22 deletions

View file

@ -1,3 +1,12 @@
2018-06-04 Eric Botcazou <ebotcazou@adacore.com>
* gimple-ssa-store-merging.c (struct merged_store_group): Move up
bit_insertion field and declare can_be_merged_into method.
(merged_store_group::can_be_merged_into): New method.
(imm_store_chain_info::coalesce_immediate): Call it to decide whether
consecutive non-overlapping stores can be merged. Turn MEM_REF stores
into BIT_INSERT_EXPR stores if the group contains a non-MEM_REF store.
2018-06-04 Richard Biener <rguenther@suse.de>
PR tree-optimization/85955

View file

@ -1426,6 +1426,7 @@ struct merged_store_group
unsigned int load_align[2];
unsigned int first_order;
unsigned int last_order;
bool bit_insertion;
auto_vec<store_immediate_info *> stores;
/* We record the first and last original statements in the sequence because
@ -1435,10 +1436,10 @@ struct merged_store_group
gimple *first_stmt;
unsigned char *val;
unsigned char *mask;
bool bit_insertion;
merged_store_group (store_immediate_info *);
~merged_store_group ();
bool can_be_merged_into (store_immediate_info *);
void merge_into (store_immediate_info *);
void merge_overlapping (store_immediate_info *);
bool apply_stores ();
@ -1851,8 +1852,47 @@ merged_store_group::~merged_store_group ()
XDELETEVEC (val);
}
/* Return true if the store described by INFO can be merged into the group. */
bool
merged_store_group::can_be_merged_into (store_immediate_info *info)
{
/* Do not merge bswap patterns. */
if (info->rhs_code == LROTATE_EXPR)
return false;
/* The canonical case. */
if (info->rhs_code == stores[0]->rhs_code)
return true;
/* BIT_INSERT_EXPR is compatible with INTEGER_CST. */
if (info->rhs_code == BIT_INSERT_EXPR && stores[0]->rhs_code == INTEGER_CST)
return true;
if (stores[0]->rhs_code == BIT_INSERT_EXPR && info->rhs_code == INTEGER_CST)
return true;
/* We can turn MEM_REF into BIT_INSERT_EXPR for bit-field stores. */
if (info->rhs_code == MEM_REF
&& (stores[0]->rhs_code == INTEGER_CST
|| stores[0]->rhs_code == BIT_INSERT_EXPR)
&& info->bitregion_start == stores[0]->bitregion_start
&& info->bitregion_end == stores[0]->bitregion_end)
return true;
if (stores[0]->rhs_code == MEM_REF
&& (info->rhs_code == INTEGER_CST
|| info->rhs_code == BIT_INSERT_EXPR)
&& info->bitregion_start == stores[0]->bitregion_start
&& info->bitregion_end == stores[0]->bitregion_end)
return true;
return false;
}
/* Helper method for merge_into and merge_overlapping to do
the common part. */
void
merged_store_group::do_merge (store_immediate_info *info)
{
@ -2673,12 +2713,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
Merge it into the current store group. There can be gaps in between
the stores, but there can't be gaps in between bitregions. */
else if (info->bitregion_start <= merged_store->bitregion_end
&& info->rhs_code != LROTATE_EXPR
&& (info->rhs_code == merged_store->stores[0]->rhs_code
|| (info->rhs_code == INTEGER_CST
&& merged_store->stores[0]->rhs_code == BIT_INSERT_EXPR)
|| (info->rhs_code == BIT_INSERT_EXPR
&& merged_store->stores[0]->rhs_code == INTEGER_CST)))
&& merged_store->can_be_merged_into (info))
{
store_immediate_info *infof = merged_store->stores[0];
@ -2696,21 +2731,41 @@ imm_store_chain_info::coalesce_immediate_stores ()
std::swap (info->ops[0], info->ops[1]);
info->ops_swapped_p = true;
}
if ((infof->ops[0].base_addr
? compatible_load_p (merged_store, info, base_addr, 0)
: !info->ops[0].base_addr)
&& (infof->ops[1].base_addr
? compatible_load_p (merged_store, info, base_addr, 1)
: !info->ops[1].base_addr)
&& check_no_overlap (m_store_info, i, info->rhs_code,
MAX (merged_store->last_order,
info->order),
MAX (merged_store->start
+ merged_store->width,
info->bitpos + info->bitsize)))
if (check_no_overlap (m_store_info, i, info->rhs_code,
MAX (merged_store->last_order,
info->order),
MAX (merged_store->start
+ merged_store->width,
info->bitpos + info->bitsize)))
{
merged_store->merge_into (info);
goto done;
/* Turn MEM_REF into BIT_INSERT_EXPR for bit-field stores. */
if (info->rhs_code == MEM_REF && infof->rhs_code != MEM_REF)
{
info->rhs_code = BIT_INSERT_EXPR;
info->ops[0].val = gimple_assign_rhs1 (info->stmt);
info->ops[0].base_addr = NULL_TREE;
}
else if (infof->rhs_code == MEM_REF && info->rhs_code != MEM_REF)
{
store_immediate_info *infoj;
unsigned int j;
FOR_EACH_VEC_ELT (merged_store->stores, j, infoj)
{
infoj->rhs_code = BIT_INSERT_EXPR;
infoj->ops[0].val = gimple_assign_rhs1 (infoj->stmt);
infoj->ops[0].base_addr = NULL_TREE;
}
}
if ((infof->ops[0].base_addr
? compatible_load_p (merged_store, info, base_addr, 0)
: !info->ops[0].base_addr)
&& (infof->ops[1].base_addr
? compatible_load_p (merged_store, info, base_addr, 1)
: !info->ops[1].base_addr))
{
merged_store->merge_into (info);
goto done;
}
}
}

View file

@ -1,3 +1,10 @@
2018-06-04 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/store_merging_21.c: New test.
* gnat.dg/opt71b.adb: Likewise.
* gnat.dg/opt71.adb: Rename into...
* gnat.dg/opt71a.adb: ...this.
2018-06-04 Richard Biener <rguenther@suse.de>
PR tree-optimization/85955

View file

@ -0,0 +1,41 @@
/* { dg-do compile } */
/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
extern void abort (void);
struct S1 {
unsigned int flag : 1;
unsigned int size : 31;
};
void foo1 (struct S1 *s, struct S1 *m)
{
s->flag = 1;
s->size = m->size;
}
void bar1 (struct S1 *s, struct S1 *m, _Bool flag)
{
s->flag = flag;
s->size = m->size;
}
struct S2 {
unsigned int size : 31;
unsigned int flag : 1;
};
void foo2 (struct S2 *s, struct S2 *m)
{
s->size = m->size;
s->flag = 1;
}
void bar2 (struct S2 *s, struct S2 *m, _Bool flag)
{
s->flag = flag;
s->size = m->size;
}
/* { dg-final { scan-tree-dump-times "Merging successful" 4 "store-merging" } } */

View file

@ -4,7 +4,7 @@
with Opt71_Pkg; use Opt71_Pkg;
procedure Opt71 (X : not null access Rec; Size : Positive) is
procedure Opt71a (X : not null access Rec; Size : Positive) is
begin
X.all := (Flag => True, Size => Size);
end;

View file

@ -0,0 +1,12 @@
-- { dg-do compile }
-- { dg-require-effective-target store_merge }
-- { dg-options "-O2 -fdump-tree-store-merging" }
with Opt71_Pkg; use Opt71_Pkg;
procedure Opt71b (X : not null access Rec; Y : not null access Rec) is
begin
X.all := (Flag => True, Size => Y.Size);
end;
-- { dg-final { scan-tree-dump "Merging successful" "store-merging" } }