re PR tree-optimization/64436 (optimize-bswapdi-3.c fails on aarch64_be-none-elf)

2015-01-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>

    gcc/
    PR tree-optimization/64436
    * tree-ssa-math-opts.c (find_bswap_or_nop_1): Move code performing the
    merge of two symbolic numbers for a bitwise OR to ...
    (perform_symbolic_merge): This. Also fix computation of the range and
    end of the symbolic number corresponding to the result of a bitwise OR.

From-SVN: r219525
This commit is contained in:
Thomas Preud'homme 2015-01-13 11:23:01 +00:00 committed by Thomas Preud'homme
parent 71aa170d28
commit af410c4c29
2 changed files with 131 additions and 77 deletions

View File

@ -1,3 +1,11 @@
2015-01-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
PR tree-optimization/64436
* tree-ssa-math-opts.c (find_bswap_or_nop_1): Move code performing the
merge of two symbolic numbers for a bitwise OR to ...
(perform_symbolic_merge): This. Also fix computation of the range and
end of the symbolic number corresponding to the result of a bitwise OR.
2014-01-13 Richard Biener <rguenther@suse.de> 2014-01-13 Richard Biener <rguenther@suse.de>
PR tree-optimization/64568 PR tree-optimization/64568

View File

@ -1822,6 +1822,123 @@ find_bswap_or_nop_load (gimple stmt, tree ref, struct symbolic_number *n)
return true; return true;
} }
/* Compute the symbolic number N representing the result of a bitwise OR on 2
symbolic number N1 and N2 whose source statements are respectively
SOURCE_STMT1 and SOURCE_STMT2. */
static gimple
perform_symbolic_merge (gimple source_stmt1, struct symbolic_number *n1,
gimple source_stmt2, struct symbolic_number *n2,
struct symbolic_number *n)
{
int i, size;
uint64_t mask;
gimple source_stmt;
struct symbolic_number *n_start;
/* Sources are different, cancel bswap if they are not memory location with
the same base (array, structure, ...). */
if (gimple_assign_rhs1 (source_stmt1) != gimple_assign_rhs1 (source_stmt2))
{
int64_t inc;
HOST_WIDE_INT start_sub, end_sub, end1, end2, end;
struct symbolic_number *toinc_n_ptr, *n_end;
if (!n1->base_addr || !n2->base_addr
|| !operand_equal_p (n1->base_addr, n2->base_addr, 0))
return NULL;
if (!n1->offset != !n2->offset ||
(n1->offset && !operand_equal_p (n1->offset, n2->offset, 0)))
return NULL;
if (n1->bytepos < n2->bytepos)
{
n_start = n1;
start_sub = n2->bytepos - n1->bytepos;
source_stmt = source_stmt1;
}
else
{
n_start = n2;
start_sub = n1->bytepos - n2->bytepos;
source_stmt = source_stmt2;
}
/* Find the highest address at which a load is performed and
compute related info. */
end1 = n1->bytepos + (n1->range - 1);
end2 = n2->bytepos + (n2->range - 1);
if (end1 < end2)
{
end = end2;
end_sub = end2 - end1;
}
else
{
end = end1;
end_sub = end1 - end2;
}
n_end = (end2 > end1) ? n2 : n1;
/* Find symbolic number whose lsb is the most significant. */
if (BYTES_BIG_ENDIAN)
toinc_n_ptr = (n_end == n1) ? n2 : n1;
else
toinc_n_ptr = (n_start == n1) ? n2 : n1;
n->range = end - n_start->bytepos + 1;
/* Check that the range of memory covered can be represented by
a symbolic number. */
if (n->range > 64 / BITS_PER_MARKER)
return NULL;
/* Reinterpret byte marks in symbolic number holding the value of
bigger weight according to target endianness. */
inc = BYTES_BIG_ENDIAN ? end_sub : start_sub;
size = TYPE_PRECISION (n1->type) / BITS_PER_UNIT;
for (i = 0; i < size; i++, inc <<= BITS_PER_MARKER)
{
unsigned marker =
(toinc_n_ptr->n >> (i * BITS_PER_MARKER)) & MARKER_MASK;
if (marker && marker != MARKER_BYTE_UNKNOWN)
toinc_n_ptr->n += inc;
}
}
else
{
n->range = n1->range;
n_start = n1;
source_stmt = source_stmt1;
}
if (!n1->alias_set
|| alias_ptr_types_compatible_p (n1->alias_set, n2->alias_set))
n->alias_set = n1->alias_set;
else
n->alias_set = ptr_type_node;
n->vuse = n_start->vuse;
n->base_addr = n_start->base_addr;
n->offset = n_start->offset;
n->bytepos = n_start->bytepos;
n->type = n_start->type;
size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
for (i = 0, mask = MARKER_MASK; i < size; i++, mask <<= BITS_PER_MARKER)
{
uint64_t masked1, masked2;
masked1 = n1->n & mask;
masked2 = n2->n & mask;
if (masked1 && masked2 && masked1 != masked2)
return NULL;
}
n->n = n1->n | n2->n;
return source_stmt;
}
/* find_bswap_or_nop_1 invokes itself recursively with N and tries to perform /* find_bswap_or_nop_1 invokes itself recursively with N and tries to perform
the operation given by the rhs of STMT on the result. If the operation the operation given by the rhs of STMT on the result. If the operation
could successfully be executed the function returns a gimple stmt whose could successfully be executed the function returns a gimple stmt whose
@ -1948,10 +2065,8 @@ find_bswap_or_nop_1 (gimple stmt, struct symbolic_number *n, int limit)
if (rhs_class == GIMPLE_BINARY_RHS) if (rhs_class == GIMPLE_BINARY_RHS)
{ {
int i, size;
struct symbolic_number n1, n2; struct symbolic_number n1, n2;
uint64_t mask; gimple source_stmt, source_stmt2;
gimple source_stmt2;
if (code != BIT_IOR_EXPR) if (code != BIT_IOR_EXPR)
return NULL; return NULL;
@ -1981,80 +2096,11 @@ find_bswap_or_nop_1 (gimple stmt, struct symbolic_number *n, int limit)
(n1.vuse && !operand_equal_p (n1.vuse, n2.vuse, 0))) (n1.vuse && !operand_equal_p (n1.vuse, n2.vuse, 0)))
return NULL; return NULL;
if (gimple_assign_rhs1 (source_stmt1) source_stmt =
!= gimple_assign_rhs1 (source_stmt2)) perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n);
{
int64_t inc;
HOST_WIDE_INT off_sub;
struct symbolic_number *n_ptr;
if (!n1.base_addr || !n2.base_addr if (!source_stmt)
|| !operand_equal_p (n1.base_addr, n2.base_addr, 0))
return NULL; return NULL;
if (!n1.offset != !n2.offset ||
(n1.offset && !operand_equal_p (n1.offset, n2.offset, 0)))
return NULL;
/* We swap n1 with n2 to have n1 < n2. */
if (n2.bytepos < n1.bytepos)
{
struct symbolic_number tmpn;
tmpn = n2;
n2 = n1;
n1 = tmpn;
source_stmt1 = source_stmt2;
}
off_sub = n2.bytepos - n1.bytepos;
/* Check that the range of memory covered can be represented by
a symbolic number. */
if (off_sub + n2.range > 64 / BITS_PER_MARKER)
return NULL;
n->range = n2.range + off_sub;
/* Reinterpret byte marks in symbolic number holding the value of
bigger weight according to target endianness. */
inc = BYTES_BIG_ENDIAN ? off_sub + n2.range - n1.range : off_sub;
size = TYPE_PRECISION (n1.type) / BITS_PER_UNIT;
if (BYTES_BIG_ENDIAN)
n_ptr = &n1;
else
n_ptr = &n2;
for (i = 0; i < size; i++, inc <<= BITS_PER_MARKER)
{
unsigned marker =
(n_ptr->n >> (i * BITS_PER_MARKER)) & MARKER_MASK;
if (marker && marker != MARKER_BYTE_UNKNOWN)
n_ptr->n += inc;
}
}
else
n->range = n1.range;
if (!n1.alias_set
|| alias_ptr_types_compatible_p (n1.alias_set, n2.alias_set))
n->alias_set = n1.alias_set;
else
n->alias_set = ptr_type_node;
n->vuse = n1.vuse;
n->base_addr = n1.base_addr;
n->offset = n1.offset;
n->bytepos = n1.bytepos;
n->type = n1.type;
size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
for (i = 0, mask = MARKER_MASK; i < size;
i++, mask <<= BITS_PER_MARKER)
{
uint64_t masked1, masked2;
masked1 = n1.n & mask;
masked2 = n2.n & mask;
if (masked1 && masked2 && masked1 != masked2)
return NULL;
}
n->n = n1.n | n2.n;
if (!verify_symbolic_number_p (n, stmt)) if (!verify_symbolic_number_p (n, stmt))
return NULL; return NULL;
@ -2063,7 +2109,7 @@ find_bswap_or_nop_1 (gimple stmt, struct symbolic_number *n, int limit)
default: default:
return NULL; return NULL;
} }
return source_stmt1; return source_stmt;
} }
return NULL; return NULL;
} }