Adam Nemet wrote:
I am trying to understand the checkin by Jeff Law from about 11 years ago:
r19204 | law | 1998-04-14 01:04:21 -0700 (Tue, 14 Apr 1998) | 4 lines
* combine.c (simplify_rtx, case TRUNCATE): Respect value of
TRULY_NOOP_TRUNCATION.
Index: combine.c
===================================================================
--- combine.c (revision 19018)
+++ combine.c (revision 19204)
@@ -3736,7 +3736,9 @@ simplify_rtx (x, op0_mode, last, in_dest
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
break;
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), NULL_RTX, 0));
This optimization simplifies the input to a truncate by only computing bits
that won't be eliminated by the truncation. Normally these are the bits in
the output mode mask. Note that the optimization does not change the truncate
into a low-part subreg, which would pretty automatically warrant the
TRULY_NOOP_TRUNCATION check.
Specifically I am curious if this was prompted by MIPS (or SH) or maybe some
other target that have a notion of truncate different from MIPS.
force_to_mode was broken WRT truncate before my patch in 2006:
http://gcc.gnu.org/ml/gcc-patches/2006-01/msg00553.html
so maybe the Jeff's patch was just trying to avoid the call to force_to_mode.
Anyhow, I don't think that the above transformation is illegal for MIPS64.
When truncating to SI mode the bits outside the resulting SI mode will all be
copies of the SI mode sign bit so their input values are obviously irrelevant.
For QI and HI modes the representation requires the upper 32 bits in the
64-bit word to be copies of the 31st bit. The transformation might change the
31 bits so it can affect the the resulting bits in the 64-bit word. This
however should have no visible effect. Operations on QI- and HI-mode values
are performed in SI mode with proper extensions before the operation if bits
outside the mode would affect the result.
I also tried a few things after removing the above check. Boostrapping and
regtesting on mips64octeon-linux was successful so was regtesting on
mipsisa64r2-elf. The assembly output of gcc.c-torture/execute/*.c improved
as:
13 files changed, 73 insertions(+), 99 deletions(-)
The changes typically remove zero and sign-extensions before a subsequent
truncation.
Any further information on this subject would be very much appreciated.
I can't be 100% sure, but I believe this was installed to deal with
problems related to a 64bit mips chip.
Assuming I've found the right thread in my personal mail archives (I've
extracted the most relevant parts of the conversation)
I wrote (in 1998):
Imagine a 64bit mips part (like that's hard :-)
Integer comparisons in the hardware are always done with 64bits
of precision.
Consider this code:
(insn 21 18 22 (set (reg:DI 86)
(ashiftrt:DI (reg/v:DI 83)
(const_int 32))) 222 {ashrdi3_internal4} (insn_list 15 (nil))
(nil))
(insn 22 21 24 (set (reg:SI 87)
(truncate:SI (reg:DI 86))) 112 {truncdisi2} (insn_list 21 (nil))
(expr_list:REG_DEAD (reg:DI 86)
(nil)))
(jump_insn 24 22 26 (set (pc)
(if_then_else (ge:SI (reg:SI 87)
(const_int 0))
(label_ref 36)
(pc))) 241 {branch_zero} (insn_list 22 (nil))
(expr_list:REG_DEAD (reg:SI 87)
Combine will turn that into (and I believe this is a valid
tranformation): [ we now know this was invalid... ]
(insn 22 21 24 (set (subreg:DI (reg:SI 87) 0)
(lshiftrt:DI (reg/v:DI 83)
(const_int 32))) 232 {lshrdi3_internal4} (insn_list 15 (nil))
(nil))
(jump_insn 24 22 26 (set (pc)
(if_then_else (ge:SI (reg:SI 87)
(const_int 0))
(label_ref 36)
(pc))) 241 {branch_zero} (insn_list 22 (nil))
(expr_list:REG_DEAD (reg:SI 87)
(nil)))
(nil)))
;; End of basic block 0
Note that insn 22 uses a logical shift -- the net result will
be that the value placed into reg87 is no longer sign extended
from 32 to 64 bits.
This causes serious grief when we try to perform a signed comparison
with zero. I suspect it would cause major headaches for arithmetic
operations too.
Ian wrote (in 1998):
> For the MIPS port, it is not valid to examine a reg:DI in reg:SI mode
> without using truncate. I don't know why that is happening. Perhaps
> something is failing to check TRULY_NOOP_TRUNCATION, which I believe
> is intended to prohibit this type of operation.
And a later message from Jim:
Truncate converts a value from a larger to a smaller mode in a machine
dependent way.
A subreg just chops off the high bits. A truncate does not. The name might
be a little confusing, but the whole point of truncate is to have something
that operates differently than a subreg.
Combine is clearly making an invalid transformation.
[ back to the present ]
I think we finally agreed that combine was incorrectly changing the
TRUNCATE (which the MIPS backend ensured always resulted in 32bit sign
extended value) into a SUBREG (which was a 32bit non-sign-extended value).
Unfortunately, I can't find the message where I posted the patch to the
egcs list for review. I did find a later patch on Oct 5, 1998 which
might be related, but I don't see any discussion. It's also terribly
unfortunate that I don't see testcases for either -- however, that would
lead me to believe both patches were fixing a problem in the existing
GCC testsuite at the time that were triggering on the MIPS part in question.
The later patch was:
r22835 | law | 1998-10-05 03:05:58 -0600 (Mon, 05 Oct 1998) | 4 lines
* combine.c (simplify_rtx): Do not replace TRUNCATE with a SUBREG if
truncation is not a no-op.
I wasn't trying to avoid the call to force_to_mode, but instead trying
to avoid combine turning a TRUNCATE into a SUBREG.
jeff