This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR61306: improve handling of sign and cast in bswap


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  <thomas.preudhomme@arm.com>

	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  <thomas.preudhomme@arm.com>

	* gcc.c-torture/execute/pr61306.c: New test.

Patch is in attachment. Is this ok for trunk?

Best regards,

Thomas

Attachment: PR61306.1.0.diff
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]