I am porting gcc-4.4.3 to TILE-Gx, a 64-bit VLIW RISC.  It's gone
pretty well so far; most tests work, Linux builds, etc.  Thanks for
writing such good documentation.

This chip, like MIPS64, maintains the invariant that SImode values in
DImode registers are always sign-extended.  So I have implemented
PROMOTE_MODE, TARGET_MODE_REP_EXTENDED and LOAD_EXTEND_OP accordingly,
and made sure my .md file always preserves this invariant.

This almost works, but testing has shown two cases that break this
invariant, and I want to know if it's my fault.

The problem is that 'widen_bswap' and 'expand_divmod' each produce a
DImode value whose high 32 bits are known to be zero, and then simply
'gen_lowpart' the DImode value to convert it to SImode.  This produces
a SUBREG, not a 'truncate' rtx, so I end up with a register that is
incorrectly zero-extended.

Am I doing something wrong, or are these functions incorrect?  As far
as I can tell, gen_lowpart is not expected to force a sign-extension
operation.  But SUBREG rules are a bit subtle so I could be missing
something.

Everything works fine if I modify 'widen_bswap' and 'expand_divmod'
to do this instead of 'return gen_lowpart (mode, x)':

  return simplify_gen_unary (TRUNCATE, mode, x, GET_MODE (x));

Since the high bits are already zero, that would be less efficient on
most platforms, so guarding it with something like this would probably
be smarter:

  if (targetm.mode_rep_extended (mode, GET_MODE(x)) == SIGN_EXTEND)
    return simplify_gen_unary (TRUNCATE, mode, x, GET_MODE (x));

I'm happy to believe I'm doing something wrong in my back end, but I'm
not sure what that would be.  I could also believe these are obscure
edge cases no one cared about before.  Any tips would be appreciated.
Thanks!

-Mat

Reply via email to