This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch for i386 string operations
- To: egcs-patches at egcs dot cygnus dot com, rth at cygnus dot com
- Subject: Patch for i386 string operations
- From: Jan Hubicka <hubicka at atrey dot karlin dot mff dot cuni dot cz>
- Date: Mon, 10 Jan 2000 12:50:29 +0100
Hi
This patch rewrites movstrsi expander to expand into real instructions
and adds several patterns for rep ; movsb, rep ; movsl, movsw and movwb
instructions.
Unlike my patch from August it don't attempt to handle more cases than
the old expander, so it is quite simple.
Unlike the old expander I am now using simple rep ; movsb for optimize_size
and !optimize.
I've also added simple code to avoid single string operations (movsb, movsw
instructions) controled by the TARGET_SINGLE_STRINGOP macro.
Once we agree on the scheme, I will rewrite other string operations and
add new optimizations (inlining of variable size stringops, alignment
handling etc. ) later.
San Jan 9 05:14:37 CET 2000 Jan Hubicka <jh@suse.cz>
* i386.md (movstrsi expander): Rewrite.
(movstrsi_1 insn): Deleted.
(strmovhi, strmovqi expander): New expanders.
(movshi_1, movsqi_1, rep_movsi, rep_movqi): New patterns.
* i386.c (x86_single_stringop): New global variable.
* i386.h (x86_single_stringop): Declare.
(TARGET_SINGLE_STRINGOP): New macro.
*** i386.md.nomemcpy Sun Jan 9 05:14:05 2000
--- i386.md Sun Jan 9 05:14:09 2000
***************
*** 7822,7892 ****
[(set_attr "type" "cld")])
(define_expand "movstrsi"
! [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
! (match_operand:BLK 1 "memory_operand" ""))
! (use (match_operand:SI 2 "const_int_operand" ""))
! (use (match_operand:SI 3 "const_int_operand" ""))
! (use (reg:SI 19))
! (clobber (match_scratch:SI 4 ""))
! (clobber (match_dup 5))
! (clobber (match_dup 6))])]
""
"
{
! rtx addr0, addr1;
if (GET_CODE (operands[2]) != CONST_INT)
FAIL;
! addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
! addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
! operands[5] = addr0;
! operands[6] = addr1;
! operands[0] = change_address (operands[0], VOIDmode, addr0);
! operands[1] = change_address (operands[1], VOIDmode, addr1);
! emit_insn (gen_cld ());
}")
;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi & %esi.
! (define_insn "*movstrsi_1"
! [(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
! (mem:BLK (match_operand:SI 1 "address_operand" "S")))
! (use (match_operand:SI 2 "const_int_operand" "n"))
! (use (match_operand:SI 3 "immediate_operand" "i"))
! (use (reg:SI 19))
! (clobber (match_scratch:SI 4 "=&c"))
! (clobber (match_dup 0))
! (clobber (match_dup 1))]
! ""
! "*
! {
! rtx xops[2];
! if (GET_CODE (operands[2]) == CONST_INT)
! {
! if (INTVAL (operands[2]) & ~0x03)
! {
! xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff);
! xops[1] = operands[4];
! output_asm_insn (\"mov{l}\\t{%0, %1|%1,%0}\", xops);
! output_asm_insn (\"{rep\;movsl|rep movsd}\", xops);
! }
! if (INTVAL (operands[2]) & 0x02)
! output_asm_insn (\"movsw\", operands);
! if (INTVAL (operands[2]) & 0x01)
! output_asm_insn (\"movsb\", operands);
! }
! else
! abort ();
! RET;
! }"
! [(set_attr "type" "multi")])
(define_expand "clrstrsi"
[(set (reg:SI 19) (const_int 0))
--- 7822,7987 ----
[(set_attr "type" "cld")])
(define_expand "movstrsi"
! [(use (match_operand:BLK 0 "memory_operand" ""))
! (use (match_operand:BLK 1 "memory_operand" ""))
! (use (match_operand:SI 2 "const_int_operand" ""))
! (use (match_operand:SI 3 "const_int_operand" ""))]
""
"
{
! rtx srcreg, destreg, countreg;
if (GET_CODE (operands[2]) != CONST_INT)
FAIL;
! destreg = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
! srcreg = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
! emit_insn (gen_cld());
! /* When optimizing for size emit simple rep ; movsb instruction. */
! if (!optimize || optimize_size)
! {
! countreg = copy_to_mode_reg (SImode, operands[2]);
! emit_insn (gen_rep_movqi (destreg, srcreg, countreg,
! destreg, srcreg, countreg));
! }
! else
! {
! if (INTVAL (operands[2]) & ~0x03)
! {
! countreg = copy_to_mode_reg (SImode,
! GEN_INT ((INTVAL (operands[2]) >> 2)
! & 0x3fffffff));
! emit_insn (gen_rep_movsi (destreg, srcreg, countreg,
! destreg, srcreg, countreg));
! }
! if (INTVAL (operands[2]) & 0x02)
! emit_insn (gen_strmovhi (destreg, srcreg));
! if (INTVAL (operands[2]) & 0x01)
! emit_insn (gen_strmovqi (destreg, srcreg));
! }
! DONE;
! }")
!
! ;; Most CPUs don't like single string operations
! ;; Handle this case here to simplify previous expander.
!
! (define_expand "strmovhi"
! [(set (match_dup 2)
! (mem:HI (match_operand:SI 1 "register_operand" "")))
! (set (mem:HI (match_operand:SI 0 "register_operand" ""))
! (match_dup 2))
! (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 2)))
! (clobber (reg:CC 17))])
! (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 2)))
! (clobber (reg:CC 17))])]
! ""
! "
! {
! if (TARGET_SINGLE_STRINGOP || optimize_size)
! {
! emit_insn (gen_strmovhi_1 (operands[0], operands[1], operands[0],
! operands[1]));
! DONE;
! }
! else
! operands[2] = gen_reg_rtx (HImode);
! }")
! (define_expand "strmovqi"
! [(set (match_dup 2)
! (mem:QI (match_operand:SI 1 "register_operand" "")))
! (set (mem:QI (match_operand:SI 0 "register_operand" ""))
! (match_dup 2))
! (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1)))
! (clobber (reg:CC 17))])
! (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))
! (clobber (reg:CC 17))])]
! ""
! "
! {
! if (TARGET_SINGLE_STRINGOP || optimize_size)
! {
! emit_insn (gen_strmovqi_1 (operands[0], operands[1], operands[0],
! operands[1]));
! DONE;
! }
! else
! operands[2] = gen_reg_rtx (QImode);
}")
;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi & %esi.
! (define_insn "strmovhi_1"
! [(set (mem:HI (match_operand:SI 0 "address_operand" "D"))
! (mem:HI (match_operand:SI 1 "address_operand" "S")))
! (set (match_operand:SI 2 "register_operand" "=0")
! (plus:SI (match_dup 0)
! (const_int 1)))
! (set (match_operand:SI 3 "register_operand" "=1")
! (plus:SI (match_dup 1)
! (const_int 1)))
! (use (reg:SI 19))]
! "TARGET_SINGLE_STRINGOP"
! "movsw"
! [(set_attr "type" "str")
! (set_attr "memory" "both")
! (set_attr "length_prefix" "1")])
!
! (define_insn "strmovqi_1"
! [(set (mem:QI (match_operand:SI 0 "address_operand" "D"))
! (mem:QI (match_operand:SI 1 "address_operand" "S")))
! (set (match_operand:SI 2 "register_operand" "=0")
! (plus:SI (match_dup 0)
! (const_int 1)))
! (set (match_operand:SI 3 "register_operand" "=1")
! (plus:SI (match_dup 1)
! (const_int 1)))
! (use (reg:SI 19))]
! "TARGET_SINGLE_STRINGOP || optimize_size"
! "movsb"
! [(set_attr "type" "str")
! (set_attr "memory" "both")])
! ;; It might seem that operands 3 & 4 could use predicate register_operand.
! ;; But strength reduction might offset the MEM expression. So we let
! ;; reload put the address into %edi & %esi.
! (define_insn "rep_movsi"
! [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0))
! (use (match_operand:SI 5 "register_operand" "2"))
! (set (match_operand:SI 0 "register_operand" "=D")
! (plus:SI (match_operand:SI 3 "address_operand" "0")
! (ashift:SI (match_dup 5) (const_int 5))))
! (set (match_operand:SI 1 "register_operand" "=S")
! (plus:SI (match_operand:SI 4 "address_operand" "1")
! (ashift:SI (match_dup 5) (const_int 5))))
! (set (mem:BLK (match_dup 3))
! (mem:BLK (match_dup 4)))
! (use (reg:SI 19))]
! ""
! "rep\;movsl|rep movsd"
! [(set_attr "type" "str")
! (set_attr "length_prefix" "1")
! (set_attr "memory" "both")])
!
! (define_insn "rep_movqi"
! [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0))
! (use (match_operand:SI 5 "register_operand" "2"))
! (set (match_operand:SI 0 "register_operand" "=D")
! (plus:SI (match_operand:SI 3 "address_operand" "0") (match_dup 5)))
! (set (match_operand:SI 1 "register_operand" "=S")
! (plus:SI (match_operand:SI 4 "address_operand" "1") (match_dup 5)))
! (set (mem:BLK (match_dup 3))
! (mem:BLK (match_dup 4)))
! (use (reg:SI 19))]
! ""
! "rep\;movsb|rep movsb"
! [(set_attr "type" "str")
! (set_attr "length_prefix" "1")
! (set_attr "memory" "both")])
(define_expand "clrstrsi"
[(set (reg:SI 19) (const_int 0))
*** ../i386.old/i386.h Sun Jan 9 03:14:53 2000
--- i386.h Sun Jan 9 03:35:21 2000
*************** extern const int x86_double_with_add, x8
*** 161,167 ****
extern const int x86_use_loop, x86_use_fiop, x86_use_mov0;
extern const int x86_use_cltd, x86_read_modify_write;
extern const int x86_read_modify, x86_split_long_moves;
! extern const int x86_promote_QImode;
#define TARGET_USE_LEAVE (x86_use_leave & CPUMASK)
#define TARGET_PUSH_MEMORY (x86_push_memory & CPUMASK)
--- 161,167 ----
extern const int x86_use_loop, x86_use_fiop, x86_use_mov0;
extern const int x86_use_cltd, x86_read_modify_write;
extern const int x86_read_modify, x86_split_long_moves;
! extern const int x86_promote_QImode, x86_single_stringop;
#define TARGET_USE_LEAVE (x86_use_leave & CPUMASK)
#define TARGET_PUSH_MEMORY (x86_push_memory & CPUMASK)
*************** extern const int x86_promote_QImode;
*** 184,189 ****
--- 184,190 ----
#define TARGET_READ_MODIFY_WRITE (x86_read_modify_write & CPUMASK)
#define TARGET_READ_MODIFY (x86_read_modify & CPUMASK)
#define TARGET_PROMOTE_QImode (x86_promote_QImode & CPUMASK)
+ #define TARGET_SINGLE_STRINGOP (x86_single_stringop & CPUMASK)
#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
*** ../i386.old/i386.c Sun Jan 9 03:14:53 2000
--- i386.c Sun Jan 9 03:36:05 2000
*************** const int x86_read_modify_write = ~m_PEN
*** 206,211 ****
--- 206,212 ----
const int x86_read_modify = ~(m_PENT | m_PPRO);
const int x86_split_long_moves = m_PPRO;
const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486;
+ const int x86_single_stringop = m_386;
#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))