re PR middle-end/22156 (bit-field copying regressed)

PR middle-end/22156
Temporarily revert:
2007-04-06  Andreas Tobler  <a.tobler@schweiz.org>
2007-04-05  Alexandre Oliva  <aoliva@redhat.com>
* tree-sra.c (try_instantiate_multiple_fields): Needlessly
initialize align to silence bogus warning.
2007-04-05  Alexandre Oliva  <aoliva@redhat.com>
* tree-sra.c (struct sra_elt): Add in_bitfld_block.  Remove
all_no_warning.
(struct sra_walk_fns): Remove use_all parameter from use.
(sra_hash_tree): Handle BIT_FIELD_REFs.
(sra_elt_hash): Don't hash bitfld blocks.
(sra_elt_eq): Skip them in parent compares as well.  Handle
BIT_FIELD_REFs.
(sra_walk_expr): Don't maintain or pass down use_all_p.
(scan_use): Remove use_all parameter.
(scalarize_use): Likewise.  Re-expand assignment to
BIT_FIELD_REF of gimple_reg.  De-scalarize before input or
output, and re-scalarize after output.  Don't mark anything
for no warning.
(scalarize_ldst): Adjust.
(scalarize_walk_gimple_modify_statement): Likewise.
(build_element_name_1): Handle BIT_FIELD_REFs.
(instantiate_element): Don't warn for any element whose parent
is used as a whole.
(instantiate_missing_elements_1): Return the sra_elt.
(canon_type_for_field): New.
(try_instantiate_multiple_fields): New.
(instantiate_missing_elemnts): Use them.
(mark_no_warning): Removed.
(generate_one_element_ref): Handle BIT_FIELD_REFs.
(REPLDUP, sra_build_elt_assignment): New.
(generate_copy_inout): Use them.
(generate_element_copy): Likewise.  Handle bitfld differences.
(generate_element_zero): Don't recurse for blocks.  Use
sra_build_elt_assignment.
(generate_one_element_int): Take elt instead of var.  Use
sra_build_elt_assignment.
(generate_element_init_1): Adjust.
(scalarize_use, scalarize_copy): Use REPLDUP.
(scalarize_ldst): Move assert before dereference.
(dump_sra_elt_name): Handle BIT_FIELD_REFs.

From-SVN: r124302
This commit is contained in:
Alexandre Oliva 2007-04-30 17:41:11 +00:00 committed by Alexandre Oliva
parent ab44f2818c
commit 143569a85c
2 changed files with 104 additions and 525 deletions

View File

@ -1,3 +1,49 @@
2007-04-30 Alexandre Oliva <aoliva@redhat.com>
PR middle-end/22156
Temporarily revert:
2007-04-06 Andreas Tobler <a.tobler@schweiz.org>
* tree-sra.c (sra_build_elt_assignment): Initialize min/maxshift.
2007-04-05 Alexandre Oliva <aoliva@redhat.com>
* tree-sra.c (try_instantiate_multiple_fields): Needlessly
initialize align to silence bogus warning.
2007-04-05 Alexandre Oliva <aoliva@redhat.com>
* tree-sra.c (struct sra_elt): Add in_bitfld_block. Remove
all_no_warning.
(struct sra_walk_fns): Remove use_all parameter from use.
(sra_hash_tree): Handle BIT_FIELD_REFs.
(sra_elt_hash): Don't hash bitfld blocks.
(sra_elt_eq): Skip them in parent compares as well. Handle
BIT_FIELD_REFs.
(sra_walk_expr): Don't maintain or pass down use_all_p.
(scan_use): Remove use_all parameter.
(scalarize_use): Likewise. Re-expand assignment to
BIT_FIELD_REF of gimple_reg. De-scalarize before input or
output, and re-scalarize after output. Don't mark anything
for no warning.
(scalarize_ldst): Adjust.
(scalarize_walk_gimple_modify_statement): Likewise.
(build_element_name_1): Handle BIT_FIELD_REFs.
(instantiate_element): Don't warn for any element whose parent
is used as a whole.
(instantiate_missing_elements_1): Return the sra_elt.
(canon_type_for_field): New.
(try_instantiate_multiple_fields): New.
(instantiate_missing_elemnts): Use them.
(mark_no_warning): Removed.
(generate_one_element_ref): Handle BIT_FIELD_REFs.
(REPLDUP, sra_build_elt_assignment): New.
(generate_copy_inout): Use them.
(generate_element_copy): Likewise. Handle bitfld differences.
(generate_element_zero): Don't recurse for blocks. Use
sra_build_elt_assignment.
(generate_one_element_int): Take elt instead of var. Use
sra_build_elt_assignment.
(generate_element_init_1): Adjust.
(scalarize_use, scalarize_copy): Use REPLDUP.
(scalarize_ldst): Move assert before dereference.
(dump_sra_elt_name): Handle BIT_FIELD_REFs.
2007-04-30 Andrew Pinski <andrew_pinski@playstation.sony.com>
PR C++/31721

View File

@ -147,10 +147,6 @@ struct sra_elt
/* True if there is BIT_FIELD_REF on the lhs with a vector. */
bool is_vector_lhs;
/* 1 if the element is a field that is part of a block, 2 if the field
is the block itself, 0 if it's neither. */
char in_bitfld_block;
};
#define IS_ELEMENT_FOR_GROUP(ELEMENT) (TREE_CODE (ELEMENT) == RANGE_EXPR)
@ -465,12 +461,6 @@ sra_hash_tree (tree t)
h = iterative_hash_expr (DECL_FIELD_BIT_OFFSET (t), h);
break;
case BIT_FIELD_REF:
/* Don't take operand 0 into account, that's our parent. */
h = iterative_hash_expr (TREE_OPERAND (t, 1), 0);
h = iterative_hash_expr (TREE_OPERAND (t, 2), h);
break;
default:
gcc_unreachable ();
}
@ -489,14 +479,12 @@ sra_elt_hash (const void *x)
h = sra_hash_tree (e->element);
/* Take into account everything except bitfield blocks back up the
chain. Given that chain lengths are rarely very long, this
should be acceptable. If we truly identify this as a performance
problem, it should work to hash the pointer value
"e->parent". */
/* Take into account everything back up the chain. Given that chain
lengths are rarely very long, this should be acceptable. If we
truly identify this as a performance problem, it should work to
hash the pointer value "e->parent". */
for (p = e->parent; p ; p = p->parent)
if (!p->in_bitfld_block)
h = (h * 65521) ^ sra_hash_tree (p->element);
h = (h * 65521) ^ sra_hash_tree (p->element);
return h;
}
@ -509,17 +497,8 @@ sra_elt_eq (const void *x, const void *y)
const struct sra_elt *a = x;
const struct sra_elt *b = y;
tree ae, be;
const struct sra_elt *ap = a->parent;
const struct sra_elt *bp = b->parent;
if (ap)
while (ap->in_bitfld_block)
ap = ap->parent;
if (bp)
while (bp->in_bitfld_block)
bp = bp->parent;
if (ap != bp)
if (a->parent != b->parent)
return false;
ae = a->element;
@ -554,11 +533,6 @@ sra_elt_eq (const void *x, const void *y)
return false;
return fields_compatible_p (ae, be);
case BIT_FIELD_REF:
return
tree_int_cst_equal (TREE_OPERAND (ae, 1), TREE_OPERAND (be, 1))
&& tree_int_cst_equal (TREE_OPERAND (ae, 2), TREE_OPERAND (be, 2));
default:
gcc_unreachable ();
}
@ -697,9 +671,10 @@ struct sra_walk_fns
/* Invoked when ELT is required as a unit. Note that ELT might refer to
a leaf node, in which case this is a simple scalar reference. *EXPR_P
points to the location of the expression. IS_OUTPUT is true if this
is a left-hand-side reference. */
is a left-hand-side reference. USE_ALL is true if we saw something we
couldn't quite identify and had to force the use of the entire object. */
void (*use) (struct sra_elt *elt, tree *expr_p,
block_stmt_iterator *bsi, bool is_output);
block_stmt_iterator *bsi, bool is_output, bool use_all);
/* Invoked when we have a copy between two scalarizable references. */
void (*copy) (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
@ -753,6 +728,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
tree expr = *expr_p;
tree inner = expr;
bool disable_scalarization = false;
bool use_all_p = false;
/* We're looking to collect a reference expression between EXPR and INNER,
such that INNER is a scalarizable decl and all other nodes through EXPR
@ -773,7 +749,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
if (disable_scalarization)
elt->cannot_scalarize = true;
else
fns->use (elt, expr_p, bsi, is_output);
fns->use (elt, expr_p, bsi, is_output, use_all_p);
}
return;
@ -860,6 +836,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
use_all:
expr_p = &TREE_OPERAND (inner, 0);
inner = expr = *expr_p;
use_all_p = true;
break;
default:
@ -907,14 +884,11 @@ sra_walk_asm_expr (tree expr, block_stmt_iterator *bsi,
sra_walk_tree_list (ASM_OUTPUTS (expr), bsi, true, fns);
}
static void sra_replace (block_stmt_iterator *bsi, tree list);
static tree sra_build_elt_assignment (struct sra_elt *elt, tree src);
/* Walk a GIMPLE_MODIFY_STMT and categorize the assignment appropriately. */
static void
sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
const struct sra_walk_fns *fns)
const struct sra_walk_fns *fns)
{
struct sra_elt *lhs_elt, *rhs_elt;
tree lhs, rhs;
@ -937,7 +911,7 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
if (!rhs_elt->is_scalar && !TREE_SIDE_EFFECTS (lhs))
fns->ldst (rhs_elt, lhs, bsi, false);
else
fns->use (rhs_elt, &GIMPLE_STMT_OPERAND (expr, 1), bsi, false);
fns->use (rhs_elt, &GIMPLE_STMT_OPERAND (expr, 1), bsi, false, false);
}
/* If it isn't scalarizable, there may be scalarizable variables within, so
@ -984,9 +958,7 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
/* Otherwise we're being used in some context that requires the
aggregate to be seen as a whole. Invoke USE. */
else
{
fns->use (lhs_elt, &GIMPLE_STMT_OPERAND (expr, 0), bsi, true);
}
fns->use (lhs_elt, &GIMPLE_STMT_OPERAND (expr, 0), bsi, true, false);
}
/* Similarly to above, LHS_ELT being null only means that the LHS as a
@ -1097,7 +1069,7 @@ find_candidates_for_sra (void)
static void
scan_use (struct sra_elt *elt, tree *expr_p ATTRIBUTE_UNUSED,
block_stmt_iterator *bsi ATTRIBUTE_UNUSED,
bool is_output ATTRIBUTE_UNUSED)
bool is_output ATTRIBUTE_UNUSED, bool use_all ATTRIBUTE_UNUSED)
{
elt->n_uses += 1;
}
@ -1205,15 +1177,6 @@ build_element_name_1 (struct sra_elt *elt)
sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (t));
obstack_grow (&sra_obstack, buffer, strlen (buffer));
}
else if (TREE_CODE (t) == BIT_FIELD_REF)
{
sprintf (buffer, "B" HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (TREE_OPERAND (t, 2), 1));
obstack_grow (&sra_obstack, buffer, strlen (buffer));
sprintf (buffer, "F" HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (TREE_OPERAND (t, 1), 1));
obstack_grow (&sra_obstack, buffer, strlen (buffer));
}
else
{
tree name = DECL_NAME (t);
@ -1246,12 +1209,9 @@ instantiate_element (struct sra_elt *elt)
{
struct sra_elt *base_elt;
tree var, base;
bool nowarn = TREE_NO_WARNING (elt->element);
for (base_elt = elt; base_elt->parent; base_elt = base_elt->parent)
if (!nowarn)
nowarn = base_elt->parent->n_uses
|| TREE_NO_WARNING (base_elt->parent->element);
continue;
base = base_elt->element;
elt->replacement = var = make_rename_temp (elt->type, "SR");
@ -1280,7 +1240,9 @@ instantiate_element (struct sra_elt *elt)
DECL_DEBUG_EXPR_IS_FROM (var) = 1;
DECL_IGNORED_P (var) = 0;
TREE_NO_WARNING (var) = nowarn;
TREE_NO_WARNING (var) = TREE_NO_WARNING (base);
if (elt->element && TREE_NO_WARNING (elt->element))
TREE_NO_WARNING (var) = 1;
}
else
{
@ -1375,7 +1337,7 @@ sum_instantiated_sizes (struct sra_elt *elt, unsigned HOST_WIDE_INT *sizep)
static void instantiate_missing_elements (struct sra_elt *elt);
static struct sra_elt *
static void
instantiate_missing_elements_1 (struct sra_elt *elt, tree child, tree type)
{
struct sra_elt *sub = lookup_element (elt, child, type, INSERT);
@ -1386,266 +1348,6 @@ instantiate_missing_elements_1 (struct sra_elt *elt, tree child, tree type)
}
else
instantiate_missing_elements (sub);
return sub;
}
/* Obtain the canonical type for field F of ELEMENT. */
static tree
canon_type_for_field (tree f, tree element)
{
tree field_type = TREE_TYPE (f);
/* canonicalize_component_ref() unwidens some bit-field types (not
marked as DECL_BIT_FIELD in C++), so we must do the same, lest we
may introduce type mismatches. */
if (INTEGRAL_TYPE_P (field_type)
&& DECL_MODE (f) != TYPE_MODE (field_type))
field_type = TREE_TYPE (get_unwidened (build3 (COMPONENT_REF,
field_type,
element,
f, NULL_TREE),
NULL_TREE));
return field_type;
}
/* Look for adjacent fields of ELT starting at F that we'd like to
scalarize as a single variable. Return the last field of the
group. */
static tree
try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
{
unsigned HOST_WIDE_INT align, oalign, word, bit, size, alchk;
enum machine_mode mode;
tree first = f, prev;
tree type, var;
struct sra_elt *block;
if (!is_sra_scalar_type (TREE_TYPE (f))
|| !host_integerp (DECL_FIELD_OFFSET (f), 1)
|| !host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)
|| !host_integerp (DECL_SIZE (f), 1)
|| lookup_element (elt, f, NULL, NO_INSERT))
return f;
/* Taking the alignment of elt->element is not enough, since it
might be just an array index or some such. We shouldn't need to
initialize align here, but our optimizers don't always realize
that, if we leave the loop without initializing align, we'll fail
the assertion right after the loop. */
align = (unsigned HOST_WIDE_INT)-1;
for (block = elt; block; block = block->parent)
if (DECL_P (block->element))
{
align = DECL_ALIGN (block->element);
break;
}
gcc_assert (block);
oalign = DECL_OFFSET_ALIGN (f);
word = tree_low_cst (DECL_FIELD_OFFSET (f), 1);
bit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
size = tree_low_cst (DECL_SIZE (f), 1);
if (align > oalign)
align = oalign;
alchk = align - 1;
alchk = ~alchk;
if ((bit & alchk) != ((bit + size - 1) & alchk))
return f;
/* Find adjacent fields in the same alignment word. */
for (prev = f, f = TREE_CHAIN (f);
f && TREE_CODE (f) == FIELD_DECL
&& is_sra_scalar_type (TREE_TYPE (f))
&& host_integerp (DECL_FIELD_OFFSET (f), 1)
&& host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)
&& host_integerp (DECL_SIZE (f), 1)
&& (HOST_WIDE_INT)word == tree_low_cst (DECL_FIELD_OFFSET (f), 1)
&& !lookup_element (elt, f, NULL, NO_INSERT);
prev = f, f = TREE_CHAIN (f))
{
unsigned HOST_WIDE_INT nbit, nsize;
nbit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
nsize = tree_low_cst (DECL_SIZE (f), 1);
if (bit + size == nbit)
{
if ((bit & alchk) != ((nbit + nsize - 1) & alchk))
break;
size += nsize;
}
else if (nbit + nsize == bit)
{
if ((nbit & alchk) != ((bit + size - 1) & alchk))
break;
bit = nbit;
size += nsize;
}
else
break;
}
f = prev;
if (f == first)
return f;
gcc_assert ((bit & alchk) == ((bit + size - 1) & alchk));
/* Try to widen the bit range so as to cover padding bits as well. */
if ((bit & ~alchk) || size != align)
{
unsigned HOST_WIDE_INT mbit = bit & alchk;
unsigned HOST_WIDE_INT msize = align;
for (f = TYPE_FIELDS (elt->type);
f; f = TREE_CHAIN (f))
{
unsigned HOST_WIDE_INT fword, fbit, fsize;
/* Skip the fields from first to prev. */
if (f == first)
{
f = prev;
continue;
}
if (!(TREE_CODE (f) == FIELD_DECL
&& host_integerp (DECL_FIELD_OFFSET (f), 1)
&& host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)))
continue;
fword = tree_low_cst (DECL_FIELD_OFFSET (f), 1);
/* If we're past the selected word, we're fine. */
if (word < fword)
continue;
fbit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
if (host_integerp (DECL_SIZE (f), 1))
fsize = tree_low_cst (DECL_SIZE (f), 1);
else
/* Assume a variable-sized field takes up all space till
the end of the word. ??? Endianness issues? */
fsize = align - fbit;
if (fword < word)
{
/* A large field might start at a previous word and
extend into the selected word. Exclude those
bits. ??? Endianness issues? */
HOST_WIDE_INT diff = fbit + fsize
- (HOST_WIDE_INT)((word - fword) * BITS_PER_UNIT + mbit);
if (diff <= 0)
continue;
mbit += diff;
msize -= diff;
}
else
{
gcc_assert (fword == word);
/* Non-overlapping, great. */
if (fbit + fsize <= mbit
|| mbit + msize <= fbit)
continue;
if (fbit <= mbit)
{
unsigned HOST_WIDE_INT diff = fbit + fsize - mbit;
mbit += diff;
msize -= diff;
}
else if (fbit > mbit)
msize -= (mbit + msize - fbit);
else
gcc_unreachable ();
}
}
bit = mbit;
size = msize;
}
/* Now we know the bit range we're interested in. Find the smallest
machine mode we can use to access it. */
for (mode = smallest_mode_for_size (size, MODE_INT);
;
mode = GET_MODE_WIDER_MODE (mode))
{
gcc_assert (mode != VOIDmode);
alchk = GET_MODE_PRECISION (mode) - 1;
alchk = ~alchk;
if ((bit & alchk) == ((bit + size - 1) & alchk))
break;
}
gcc_assert (~alchk < align);
/* Create the field group as a single variable. */
type = lang_hooks.types.type_for_mode (mode, 1);
gcc_assert (type);
var = build3 (BIT_FIELD_REF, type, NULL_TREE,
bitsize_int (size),
bitsize_int (word * BITS_PER_UNIT + bit));
BIT_FIELD_REF_UNSIGNED (var) = 1;
block = instantiate_missing_elements_1 (elt, var, type);
gcc_assert (block && block->is_scalar);
var = block->replacement;
if (((word * BITS_PER_UNIT + bit) & ~alchk)
|| (HOST_WIDE_INT)size != tree_low_cst (DECL_SIZE (var), 1))
{
block->replacement = build3 (BIT_FIELD_REF,
TREE_TYPE (block->element), var,
bitsize_int (size),
bitsize_int ((word * BITS_PER_UNIT
+ bit) & ~alchk));
BIT_FIELD_REF_UNSIGNED (block->replacement) = 1;
TREE_NO_WARNING (block->replacement) = 1;
}
block->in_bitfld_block = 2;
/* Add the member fields to the group, such that they access
portions of the group variable. */
for (f = first; f != TREE_CHAIN (prev); f = TREE_CHAIN (f))
{
tree field_type = canon_type_for_field (f, elt->element);
struct sra_elt *fld = lookup_element (block, f, field_type, INSERT);
gcc_assert (fld && fld->is_scalar && !fld->replacement);
fld->replacement = build3 (BIT_FIELD_REF, field_type, var,
DECL_SIZE (f),
bitsize_int
((word * BITS_PER_UNIT
+ (TREE_INT_CST_LOW
(DECL_FIELD_BIT_OFFSET (f))))
& ~alchk));
BIT_FIELD_REF_UNSIGNED (fld->replacement) = TYPE_UNSIGNED (field_type);
TREE_NO_WARNING (block->replacement) = 1;
fld->in_bitfld_block = 1;
}
return prev;
}
static void
@ -1661,17 +1363,21 @@ instantiate_missing_elements (struct sra_elt *elt)
for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
if (TREE_CODE (f) == FIELD_DECL)
{
tree last = try_instantiate_multiple_fields (elt, f);
tree field_type = TREE_TYPE (f);
if (last != f)
{
f = last;
continue;
}
/* canonicalize_component_ref() unwidens some bit-field
types (not marked as DECL_BIT_FIELD in C++), so we
must do the same, lest we may introduce type
mismatches. */
if (INTEGRAL_TYPE_P (field_type)
&& DECL_MODE (f) != TYPE_MODE (field_type))
field_type = TREE_TYPE (get_unwidened (build3 (COMPONENT_REF,
field_type,
elt->element,
f, NULL_TREE),
NULL_TREE));
instantiate_missing_elements_1 (elt, f,
canon_type_for_field
(f, elt->element));
instantiate_missing_elements_1 (elt, f, field_type);
}
break;
}
@ -1983,16 +1689,6 @@ generate_one_element_ref (struct sra_elt *elt, tree base)
{
tree field = elt->element;
/* We can't test elt->in_bitfld_blk here because, when this is
called from instantiate_element, we haven't set this field
yet. */
if (TREE_CODE (field) == BIT_FIELD_REF)
{
tree ret = copy_node (field);
TREE_OPERAND (ret, 0) = base;
return ret;
}
/* Watch out for compatible records with differing field lists. */
if (DECL_FIELD_CONTEXT (field) != TYPE_MAIN_VARIANT (TREE_TYPE (base)))
field = find_compatible_field (TREE_TYPE (base), field);
@ -2045,126 +1741,6 @@ sra_build_assignment (tree dst, tree src)
return build_gimple_modify_stmt (dst, src);
}
/* BIT_FIELD_REFs must not be shared. sra_build_elt_assignment()
takes care of assignments, but we must create copies for uses. */
#define REPLDUP(t) (TREE_CODE (t) != BIT_FIELD_REF ? (t) : copy_node (t))
static tree
sra_build_elt_assignment (struct sra_elt *elt, tree src)
{
tree dst = elt->replacement;
tree var, type, tmp, tmp2, tmp3;
tree list, stmt;
tree cst, cst2, mask;
tree minshift = NULL, maxshift = NULL;
if (TREE_CODE (dst) != BIT_FIELD_REF
|| !elt->in_bitfld_block)
return sra_build_assignment (REPLDUP (dst), src);
var = TREE_OPERAND (dst, 0);
/* Try to widen the assignment to the entire variable.
We need the source to be a BIT_FIELD_REF as well, such that, for
BIT_FIELD_REF<d,sz,dp> = BIT_FIELD_REF<s,sz,sp>,
if sp >= dp, we can turn it into
d = BIT_FIELD_REF<s,sp+sz,sp-dp>. */
if (elt->in_bitfld_block == 2
&& TREE_CODE (src) == BIT_FIELD_REF
&& !tree_int_cst_lt (TREE_OPERAND (src, 2), TREE_OPERAND (dst, 2)))
{
src = fold_build3 (BIT_FIELD_REF, TREE_TYPE (var),
TREE_OPERAND (src, 0),
size_binop (PLUS_EXPR, TREE_OPERAND (src, 1),
TREE_OPERAND (dst, 2)),
size_binop (MINUS_EXPR, TREE_OPERAND (src, 2),
TREE_OPERAND (dst, 2)));
BIT_FIELD_REF_UNSIGNED (src) = 1;
return sra_build_assignment (var, src);
}
if (!is_gimple_reg (var))
return sra_build_assignment (REPLDUP (dst), src);
list = alloc_stmt_list ();
cst = TREE_OPERAND (dst, 2);
if (WORDS_BIG_ENDIAN)
{
cst = size_binop (MINUS_EXPR, DECL_SIZE (var), cst);
maxshift = cst;
}
else
minshift = cst;
cst2 = size_binop (PLUS_EXPR, TREE_OPERAND (dst, 1),
TREE_OPERAND (dst, 2));
if (WORDS_BIG_ENDIAN)
{
cst2 = size_binop (MINUS_EXPR, DECL_SIZE (var), cst2);
minshift = cst2;
}
else
maxshift = cst2;
type = TREE_TYPE (var);
mask = build_int_cst_wide (type, 1, 0);
cst = int_const_binop (LSHIFT_EXPR, mask, maxshift, 1);
cst2 = int_const_binop (LSHIFT_EXPR, mask, minshift, 1);
mask = int_const_binop (MINUS_EXPR, cst, cst2, 1);
mask = fold_build1 (BIT_NOT_EXPR, type, mask);
if (!WORDS_BIG_ENDIAN)
cst2 = TREE_OPERAND (dst, 2);
tmp = make_rename_temp (type, "SR");
stmt = build_gimple_modify_stmt (tmp,
fold_build2 (BIT_AND_EXPR, type,
var, mask));
append_to_statement_list (stmt, &list);
if (is_gimple_reg (src))
tmp2 = src;
else
{
tmp2 = make_rename_temp (TREE_TYPE (src), "SR");
stmt = sra_build_assignment (tmp2, src);
append_to_statement_list (stmt, &list);
}
if (!TYPE_UNSIGNED (TREE_TYPE (tmp2))
|| TYPE_MAIN_VARIANT (TREE_TYPE (tmp2)) != TYPE_MAIN_VARIANT (type))
{
tmp3 = make_rename_temp (type, "SR");
tmp2 = fold_build3 (BIT_FIELD_REF, type, tmp2, TREE_OPERAND (dst, 1),
bitsize_int (0));
if (TREE_CODE (tmp2) == BIT_FIELD_REF)
BIT_FIELD_REF_UNSIGNED (tmp2) = 1;
stmt = sra_build_assignment (tmp3, tmp2);
append_to_statement_list (stmt, &list);
tmp2 = tmp3;
}
if (!integer_zerop (minshift))
{
tmp3 = make_rename_temp (type, "SR");
stmt = build_gimple_modify_stmt (tmp3,
fold_build2 (LSHIFT_EXPR, type,
tmp2, minshift));
append_to_statement_list (stmt, &list);
tmp2 = tmp3;
}
stmt = build_gimple_modify_stmt (var,
fold_build2 (BIT_IOR_EXPR, type,
tmp, tmp2));
append_to_statement_list (stmt, &list);
return list;
}
/* Generate a set of assignment statements in *LIST_P to copy all
instantiated elements under ELT to or from the equivalent structure
rooted at EXPR. COPY_OUT controls the direction of the copy, with
@ -2195,9 +1771,9 @@ generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
else if (elt->replacement)
{
if (copy_out)
t = sra_build_elt_assignment (elt, expr);
t = sra_build_assignment (elt->replacement, expr);
else
t = sra_build_assignment (expr, REPLDUP (elt->replacement));
t = sra_build_assignment (expr, elt->replacement);
append_to_statement_list (t, list_p);
}
else
@ -2222,19 +1798,6 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
FOR_EACH_ACTUAL_CHILD (dc, dst)
{
sc = lookup_element (src, dc->element, NULL, NO_INSERT);
if (!sc && dc->in_bitfld_block == 2)
{
struct sra_elt *dcs;
FOR_EACH_ACTUAL_CHILD (dcs, dc)
{
sc = lookup_element (src, dcs->element, NULL, NO_INSERT);
gcc_assert (sc);
generate_element_copy (dcs, sc, list_p);
}
continue;
}
gcc_assert (sc);
generate_element_copy (dc, sc, list_p);
}
@ -2245,7 +1808,7 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
gcc_assert (src->replacement);
t = sra_build_elt_assignment (dst, REPLDUP (src->replacement));
t = sra_build_assignment (dst->replacement, src->replacement);
append_to_statement_list (t, list_p);
}
}
@ -2266,9 +1829,8 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
return;
}
if (!elt->in_bitfld_block)
FOR_EACH_ACTUAL_CHILD (c, elt)
generate_element_zero (c, list_p);
FOR_EACH_ACTUAL_CHILD (c, elt)
generate_element_zero (c, list_p);
if (elt->replacement)
{
@ -2277,7 +1839,7 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
gcc_assert (elt->is_scalar);
t = fold_convert (elt->type, integer_zero_node);
t = sra_build_elt_assignment (elt, t);
t = sra_build_assignment (elt->replacement, t);
append_to_statement_list (t, list_p);
}
}
@ -2286,10 +1848,10 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
Add the result to *LIST_P. */
static void
generate_one_element_init (struct sra_elt *elt, tree init, tree *list_p)
generate_one_element_init (tree var, tree init, tree *list_p)
{
/* The replacement can be almost arbitrarily complex. Gimplify. */
tree stmt = sra_build_elt_assignment (elt, init);
tree stmt = sra_build_assignment (var, init);
gimplify_and_add (stmt, list_p);
}
@ -2318,7 +1880,7 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
{
if (elt->replacement)
{
generate_one_element_init (elt, init, list_p);
generate_one_element_init (elt->replacement, init, list_p);
elt->visited = true;
}
return result;
@ -2477,7 +2039,7 @@ sra_replace (block_stmt_iterator *bsi, tree list)
static void
scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
bool is_output)
bool is_output, bool use_all)
{
tree list = NULL, stmt = bsi_stmt (*bsi);
@ -2486,27 +2048,8 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
/* If we have a replacement, then updating the reference is as
simple as modifying the existing statement in place. */
if (is_output)
{
if (TREE_CODE (elt->replacement) == BIT_FIELD_REF
&& is_gimple_reg (TREE_OPERAND (elt->replacement, 0))
&& TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
&& &GIMPLE_STMT_OPERAND (stmt, 0) == expr_p)
{
tree newstmt = sra_build_elt_assignment
(elt, GIMPLE_STMT_OPERAND (stmt, 1));
if (TREE_CODE (newstmt) != STATEMENT_LIST)
{
tree list = alloc_stmt_list ();
append_to_statement_list (newstmt, &list);
newstmt = list;
}
sra_replace (bsi, newstmt);
return;
}
mark_all_v_defs (stmt);
}
*expr_p = REPLDUP (elt->replacement);
mark_all_v_defs (stmt);
*expr_p = elt->replacement;
update_stmt (stmt);
}
else
@ -2524,23 +2067,17 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
This optimization would be most effective if sra_walk_function
processed the blocks in dominator order. */
generate_copy_inout (elt, false, generate_element_ref (elt), &list);
if (list)
{
mark_all_v_defs (list);
sra_insert_before (bsi, list);
mark_no_warning (elt);
}
generate_copy_inout (elt, is_output, generate_element_ref (elt), &list);
if (list == NULL)
return;
mark_all_v_defs (list);
if (is_output)
sra_insert_after (bsi, list);
else
{
list = NULL;
generate_copy_inout (elt, true, generate_element_ref (elt), &list);
if (list)
{
mark_all_v_defs (list);
sra_insert_after (bsi, list);
}
sra_insert_before (bsi, list);
if (use_all)
mark_no_warning (elt);
}
}
}
@ -2564,7 +2101,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
GIMPLE_STMT_OPERAND (stmt, 0) = lhs_elt->replacement;
GIMPLE_STMT_OPERAND (stmt, 1) = REPLDUP (rhs_elt->replacement);
GIMPLE_STMT_OPERAND (stmt, 1) = rhs_elt->replacement;
update_stmt (stmt);
}
else if (lhs_elt->use_block_copy || rhs_elt->use_block_copy)
@ -2706,7 +2243,7 @@ scalarize_ldst (struct sra_elt *elt, tree other,
{
/* Since ELT is not fully instantiated, we have to leave the
block copy in place. Treat this as a USE. */
scalarize_use (elt, NULL, bsi, is_output);
scalarize_use (elt, NULL, bsi, is_output, false);
}
else
{
@ -2718,8 +2255,8 @@ scalarize_ldst (struct sra_elt *elt, tree other,
mark_all_v_defs (stmt);
generate_copy_inout (elt, is_output, other, &list);
gcc_assert (list);
mark_all_v_defs (list);
gcc_assert (list);
/* Preserve EH semantics. */
if (stmt_ends_bb_p (stmt))
@ -2815,10 +2352,6 @@ dump_sra_elt_name (FILE *f, struct sra_elt *elt)
fputc ('.', f);
print_generic_expr (f, elt->element, dump_flags);
}
else if (TREE_CODE (elt->element) == BIT_FIELD_REF)
fprintf (f, "$B" HOST_WIDE_INT_PRINT_DEC "F" HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (TREE_OPERAND (elt->element, 2), 1),
tree_low_cst (TREE_OPERAND (elt->element, 1), 1));
else if (TREE_CODE (elt->element) == RANGE_EXPR)
fprintf (f, "["HOST_WIDE_INT_PRINT_DEC".."HOST_WIDE_INT_PRINT_DEC"]",
TREE_INT_CST_LOW (TREE_OPERAND (elt->element, 0)),