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