Commit af410c4c by Thomas Preud'homme Committed by Thomas Preud'homme

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
parent 71aa170d
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
......
...@@ -1822,6 +1822,123 @@ find_bswap_or_nop_load (gimple stmt, tree ref, struct symbolic_number *n) ...@@ -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) ...@@ -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) ...@@ -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
|| !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;
/* We swap n1 with n2 to have n1 < n2. */ if (!source_stmt)
if (n2.bytepos < n1.bytepos) return NULL;
{
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) ...@@ -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;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment