When bswap replace a bitwise expression involving a memory source by a load possibly followed by a bswap, it is possible that the load has a size smaller than that of the target expression where the bitwise expression was affected. So some sort of cast is needed. But there might also be a difference between the size of the expression that was affected and the size of the load. So 3 different sizes might be involved. Consider the following example from binutils:
bfd_vma
bfd_getl16 (const void *p)
{
const bfd_byte *addr = (*const bfd_byte *) p;
return (addr[1] << 8) | addr[0];
}
Here the load will have a size of 16 bits, while the bitwise expression is an
int (don't ask me why) but is returned as a 64 bits quantity (bfd_vma maps to
the size of host registers). In this case we need 2 separate cast. One from 16
bit quantity to int with zero extension as the high bits are 0. It is always a
zero extension because bswap will not do anything in the presence of a sign
extension as depending on the initial value the result would be different
(maybe a bswap if positive number and random value if negative number). Then,
we need to cast respecting the extension that would have happen had we not
replaced the bitwise extension. Here since the bitwise expression is int, it
means we sign extend and then consider the content as being unsigned (bfd_vma
is an unsigned quantity).
When a bswap is necessary we need to do this double cast after doing the bswap
as the bswap must be done on the loaded value since a that's the size expected
by the bswap builtin. Finally, this patch also forbit any sign extension *in*
the bitwise expression as the result of the expression would then be
unpredictable (depend on the initial value).
The patch works this way:
1) prevent size extension of a bitwise expression
2) record the type of the bitwise expression instead of its size (the size can
be determined from the type)
3) use this type to perform a double cast as explained above
2014-05-30 Thomas Preud'homme <[email protected]>
PR tree-optimization/61306
* tree-ssa-math-opts.c (struct symbolic_number): Store type of
expression instead of its size.
(do_shift_rotate): Adapt to change in struct symbolic_number.
(verify_symbolic_number_p): Likewise.
(init_symbolic_number): Likewise.
(find_bswap_or_nop_1): Likewise. Also prevent optimization when the
result of the expressions is unpredictable due to sign extension.
(convert_via): New function to deal with the casting involved from the
loaded value to the target SSA.
(bswap_replace): Rename load_type in range_type to reflect it's the
type the memory accessed shall have before being casted. Select load
type according to whether a bswap needs to be done. Cast first to rhs
with zero extend and then to lhs with sign extend to keep semantic of
original stmts.
(pass_optimize_bswap::execute): Adapt to change in struct
symbolic_number. Decide if the range accessed should be signed or
unsigned before being casted to lhs type based on rhs type and size.
2014-05-29 Thomas Preud'homme <[email protected]>
* gcc.c-torture/execute/pr61306.c: New test.
Patch is in attachment. Is this ok for trunk?
Best regards,
Thomas
PR61306.1.0.diff
Description: Binary data
