I am porting gcc-4.4.3 to TILE-Gx, a straightforward 64-bit VLIW RISC. TILE-Gx,
like MIPS, maintains the invariant that an SI value in a register is always
sign extended (to DI), even if the value is unsigned.
I noticed that the default bswap32 implementation, which essentially produces
(uint32_t)(__builtin_bswap64(x) >> 32), was not leaving the resulting SI value
properly sign extended in the register.
The problem is that widen_bswap uses gen_lowpart instead of truncdisi2 to
convert the right-shifted DI value down to SI. This is not legal on all
architectures. If you look elsewhere in the same file you'll see the correct
truncation idiom being used.
-Mat
--- gcc/optabs.c.orig 2010-01-28 14:38:17.434262000 -0500
+++ gcc/optabs.c 2010-01-28 14:01:04.222750000 -0500
@@ -2726,21 +2726,22 @@
if (x != 0)
x = expand_shift (RSHIFT_EXPR, wider_mode, x,
size_int (GET_MODE_BITSIZE (wider_mode)
- GET_MODE_BITSIZE (mode)),
NULL_RTX, true);
if (x != 0)
{
if (target == 0)
target = gen_reg_rtx (mode);
- emit_move_insn (target, gen_lowpart (mode, x));
+ emit_move_insn (target,
+ simplify_gen_unary (TRUNCATE, mode, x, GET_MODE (x)));
}
else
delete_insns_since (last);
return target;
}
/* Try calculating bswap as two bswaps of two word-sized operands. */
static rtx
--
Summary: widen_bswap fails to truncate its return value properly
Product: gcc
Version: 4.4.3
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: mat at lcs dot mit dot edu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42937