This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]