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

Reply via email to