This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Removing redundant slls from 64-bit MIPS code
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: echristo at redhat dot com
- Date: Fri, 28 May 2004 08:27:20 +0100
- Subject: Removing redundant slls from 64-bit MIPS code
It's a fundamental assumption in the 64-bit MIPS port that every SImode
integer register is stored in sign-extended form. We rely on this to get
SImode comparisons right (MIPS doesn't have separate 32-bit and 64-bit
comparison insns) and to avoid unpredictable behaviour when doing 32-bit
arithmetic.
One knock-on effect is that truncdisi2 is really a sign-extension
instruction. It converts a general DImode value into a canonical
sign-extended SImode value.
Also, extendsidi2 shouldn't need to do anything when both the source
and destination are integer registers. The SImode input should already
be sign-extended.
In 3.3 and earlier, we treated SI->DI extension as a form of move
instruction, with the GPR->GPR alternative just using a "move" macro.
This was changed in 3.4 so that extendsidi2 was a real sign-extension
instruction, just like truncdisi2.
I was always a bit opposed to that change, since I thought it wasn't
necessary and could likely hide bugs (i.e. cases where SImode registers
weren't sign-extended but should have been). But size- and performance-
wise, "sll" is no worse than a "move" on most targets, so proponents of
defensive programming could quite rightly say (and did say ;) "so what"?
One thing I've wanted to try for a while, and finally got around
to doing, was restricting the GPR->GPR alternative so that the
source and destination are in the same register. We can then
"split" the instruction into nothing.
Patch below. It seems to save quite a lot of redundant "sll"
instructions on EABI64 code (which, like n64, should benefit most,
since they both have 64-bit longs and promote integers to DImode).
I compared the c-torture output of mipsisa64-elf before and after
the patch using -O2. It showed:
268 files changed, 563 insertions(+), 1179 deletions(-)
Of those 268 files, only one got bigger (by a single instruction).
The rest were all the same size or smaller.
Tested on mips-sgi-irix6.5 and mipsisa64-elf with no regressions.
IRIX seemed like a good target to test because the n64 multilibs
should exercise this code quite a lot. mipsisa64-elf has the dual
benefit of using EABI64 by default, and of having a simulator that
complains about unpredicatable behaviour.
Eric, is this OK with you?
Richard
* config/mips/mips.md (extendsidi2): Tie the source and destination
of the register alternative. Split it into nothing.
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.244
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.244 mips.md
*** config/mips/mips.md 17 May 2004 06:52:43 -0000 1.244
--- config/mips/mips.md 28 May 2004 07:18:52 -0000
*************** (define_insn ""
*** 3405,3420 ****
;; Extension insns.
;; Those for integer source operand are ordered widest source type first.
! (define_insn "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d")
! (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m")))]
"TARGET_64BIT"
"@
! sll\t%0,%1,0
lw\t%0,%1"
! [(set_attr "type" "shift,load")
! (set_attr "mode" "DI")
! (set_attr "extended_mips16" "yes,*")])
;; These patterns originally accepted general_operands, however, slightly
;; better code is generated by only accepting register_operands, and then
--- 3405,3433 ----
;; Extension insns.
;; Those for integer source operand are ordered widest source type first.
! ;; When TARGET_64BIT, all SImode integer registers should already be in
! ;; sign-extended form (see TRULY_NOOP_TRUNCATION and truncdisi2). We can
! ;; therefore get rid of register->register instructions if we constrain
! ;; the source to be in the same register as the destination.
! ;;
! ;; The register alternative has type "arith" so that the pre-reload
! ;; scheduler will treat it as a move. This reflects what happens if
! ;; the register alternative needs a reload.
! (define_insn_and_split "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d")
! (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,m")))]
"TARGET_64BIT"
"@
! #
lw\t%0,%1"
! "&& reload_completed && register_operand (operands[1], 0)"
! [(const_int 0)]
! {
! emit_note (NOTE_INSN_DELETED);
! DONE;
! }
! [(set_attr "type" "arith,load")
! (set_attr "mode" "DI")])
;; These patterns originally accepted general_operands, however, slightly
;; better code is generated by only accepting register_operands, and then