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