return false;
}
\f
-/* Try using movmd to move LENGTH bytes from memory region SRC to memory
- region DEST. The two regions do not overlap and have the common
- alignment given by ALIGNMENT. Return true on success.
-
- Using movmd for variable-length moves seems to involve some
- complex trade-offs. For instance:
-
- - Preparing for a movmd instruction is similar to preparing
- for a memcpy. The main difference is that the arguments
- are moved into er4, er5 and er6 rather than er0, er1 and er2.
-
- - Since movmd clobbers the frame pointer, we need to save
- and restore it somehow when frame_pointer_needed. This can
- sometimes make movmd sequences longer than calls to memcpy().
-
- - The counter register is 16 bits, so the instruction is only
- suitable for variable-length moves when sizeof (size_t) == 2.
- That's only true in normal mode.
-
- - We will often lack static alignment information. Falling back
- on movmd.b would likely be slower than calling memcpy(), at least
- for big moves.
-
- This function therefore only uses movmd when the length is a
- known constant, and only then if -fomit-frame-pointer is in
- effect or if we're not optimizing for size.
-
- At the moment the function uses movmd for all in-range constants,
- but it might be better to fall back on memcpy() for large moves
- if ALIGNMENT == 1. */
-
-bool
-h8sx_emit_movmd (rtx dest, rtx src, rtx length,
- HOST_WIDE_INT alignment)
-{
- if (!flag_omit_frame_pointer && optimize_size)
- return false;
-
- if (GET_CODE (length) == CONST_INT)
- {
- rtx dest_reg, src_reg, first_dest, first_src;
- HOST_WIDE_INT n;
- int factor;
-
- /* Use movmd.l if the alignment allows it, otherwise fall back
- on movmd.b. */
- factor = (alignment >= 2 ? 4 : 1);
-
- /* Make sure the length is within range. We can handle counter
- values up to 65536, although HImode truncation will make
- the count appear negative in rtl dumps. */
- n = INTVAL (length);
- if (n <= 0 || n / factor > 65536)
- return false;
-
- /* Create temporary registers for the source and destination
- pointers. Initialize them to the start of each region. */
- dest_reg = copy_addr_to_reg (XEXP (dest, 0));
- src_reg = copy_addr_to_reg (XEXP (src, 0));
-
- /* Create references to the movmd source and destination blocks. */
- first_dest = replace_equiv_address (dest, dest_reg);
- first_src = replace_equiv_address (src, src_reg);
-
- set_mem_size (first_dest, n & -factor);
- set_mem_size (first_src, n & -factor);
-
- length = copy_to_mode_reg (HImode, gen_int_mode (n / factor, HImode));
- emit_insn (gen_movmd (first_dest, first_src, length, GEN_INT (factor)));
-
- if ((n & -factor) != n)
- {
- /* Move SRC and DEST past the region we just copied.
- This is done to update the memory attributes. */
- dest = adjust_address (dest, BLKmode, n & -factor);
- src = adjust_address (src, BLKmode, n & -factor);
-
- /* Replace the addresses with the source and destination
- registers, which movmd has left with the right values. */
- dest = replace_equiv_address (dest, dest_reg);
- src = replace_equiv_address (src, src_reg);
-
- /* Mop up the left-over bytes. */
- if (n & 2)
- emit_move_insn (adjust_address (dest, HImode, 0),
- adjust_address (src, HImode, 0));
- if (n & 1)
- emit_move_insn (adjust_address (dest, QImode, n & 2),
- adjust_address (src, QImode, n & 2));
- }
- return true;
- }
- return false;
-}
-
-/* Move ADDR into er6 after pushing its old value onto the stack. */
-
-void
-h8300_swap_into_er6 (rtx addr)
-{
- rtx insn = push (HARD_FRAME_POINTER_REGNUM, false);
- if (frame_pointer_needed)
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (Pmode, gen_rtx_MEM (Pmode, stack_pointer_rtx),
- 2 * UNITS_PER_WORD));
- else
- add_reg_note (insn, REG_CFA_ADJUST_CFA,
- gen_rtx_SET (stack_pointer_rtx,
- plus_constant (Pmode, stack_pointer_rtx, 4)));
-
- emit_move_insn (hard_frame_pointer_rtx, addr);
- if (REGNO (addr) == SP_REG)
- emit_move_insn (hard_frame_pointer_rtx,
- plus_constant (Pmode, hard_frame_pointer_rtx,
- GET_MODE_SIZE (word_mode)));
-}
-
-/* Move the current value of er6 into ADDR and pop its old value
- from the stack. */
-
-void
-h8300_swap_out_of_er6 (rtx addr)
-{
- rtx insn;
-
- if (REGNO (addr) != SP_REG)
- emit_move_insn (addr, hard_frame_pointer_rtx);
-
- insn = pop (HARD_FRAME_POINTER_REGNUM);
- if (frame_pointer_needed)
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (Pmode, hard_frame_pointer_rtx,
- 2 * UNITS_PER_WORD));
- else
- add_reg_note (insn, REG_CFA_ADJUST_CFA,
- gen_rtx_SET (stack_pointer_rtx,
- plus_constant (Pmode, stack_pointer_rtx, -4)));
-}
-\f
/* Return the length of mov instruction. */
unsigned int
(set_attr "length_table" "*,movl")
(set_attr "cc" "set_zn,set_znv")])
-;; Implement block copies using movmd. Defining cpymemsi allows the full
-;; range of constant lengths (up to 0x40000 bytes when using movmd.l).
-;; See h8sx_emit_movmd for details.
-
-(define_expand "cpymemsi"
- [(use (match_operand:BLK 0 "memory_operand" ""))
- (use (match_operand:BLK 1 "memory_operand" ""))
- (use (match_operand:SI 2 "" ""))
- (use (match_operand:SI 3 "const_int_operand" ""))]
- "TARGET_H8300SX && 0"
- {
- if (h8sx_emit_movmd (operands[0], operands[1], operands[2], INTVAL (operands[3])))
- DONE;
- else
- FAIL;
- })
-
-;; Expander for generating movmd insns. Operand 0 is the destination
-;; memory region, operand 1 is the source, operand 2 is the counter
-;; register and operand 3 is the chunk size (1, 2 or 4).
-
-(define_expand "movmd"
- [(parallel
- [(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand:BLK 1 "memory_operand" ""))
- (unspec [(match_operand:HI 2 "register_operand" "")
- (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD)
- (clobber (match_dup 4))
- (clobber (match_dup 5))
- (set (match_dup 2)
- (const_int 0))])]
- "TARGET_H8300SX && 0"
- {
- operands[4] = copy_rtx (XEXP (operands[0], 0));
- operands[5] = copy_rtx (XEXP (operands[1], 0));
- })
-
-;; This is a difficult instruction to reload since operand 0 must be the
-;; frame pointer. See h8300_reg_class_from_letter for an explanation.
-
-(define_insn "movmd_internal_<mode>"
- [(set (mem:BLK (match_operand:P 3 "register_operand" "0,r"))
- (mem:BLK (match_operand:P 4 "register_operand" "1,1")))
- (unspec [(match_operand:HI 5 "register_operand" "2,2")
- (match_operand:HI 6 "const_int_operand" "n,n")] UNSPEC_MOVMD)
- (clobber (match_operand:P 0 "register_operand" "=d,??D"))
- (clobber (match_operand:P 1 "register_operand" "=f,f"))
- (set (match_operand:HI 2 "register_operand" "=c,c")
- (const_int 0))]
- "TARGET_H8300SX && 0"
- "@
- movmd%m6
- #"
- [(set_attr "length" "2,14")
- (set_attr "can_delay" "no")
- (set_attr "cc" "none,clobber")])
-
-;; Split the above instruction if the destination register isn't er6.
-;; We need a sequence like:
-;;
-;; mov.l er6,@-er7
-;; mov.l <dest>,er6
-;; movmd.sz
-;; mov.l er6,<dest>
-;; mov.l @er7+,er6
-;;
-;; where <dest> is the current destination register (operand 4).
-;; The fourth instruction will be deleted if <dest> dies here.
-
-(define_split
- [(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand:BLK 1 "memory_operand" ""))
- (unspec [(match_operand:HI 2 "register_operand" "")
- (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD)
- (clobber (match_operand:P 4 "register_operand" ""))
- (clobber (match_operand:P 5 "register_operand" ""))
- (set (match_dup 2)
- (const_int 0))]
- "TARGET_H8300SX && reload_completed
- && 0
- && REGNO (operands[4]) != DESTINATION_REG"
- [(const_int 0)]
- {
- rtx dest;
-
- h8300_swap_into_er6 (XEXP (operands[0], 0));
- dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
- emit_insn (gen_movmd (dest, operands[1], operands[2], operands[3]));
- h8300_swap_out_of_er6 (operands[4]);
- DONE;
- })
-
-;; Expand a call to stpcpy() using movsd. Operand 0 should point to
-;; the final character, but movsd leaves it pointing to the character
-;; after that.
-
-(define_expand "movstr"
- [(use (match_operand 0 "register_operand" ""))
- (use (match_operand:BLK 1 "memory_operand" ""))
- (use (match_operand:BLK 2 "memory_operand" ""))]
- "TARGET_H8300SX && 0"
- {
- operands[1] = replace_equiv_address
- (operands[1], copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
- operands[2] = replace_equiv_address
- (operands[2], copy_to_mode_reg (Pmode, XEXP (operands[2], 0)));
- emit_insn (gen_movsd (operands[1], operands[2], gen_reg_rtx (Pmode)));
- emit_insn (gen_add3_insn (operands[0], XEXP (operands[1], 0), constm1_rtx));
- DONE;
- })
-
-;; Expander for generating a movsd instruction. Operand 0 is the
-;; destination string, operand 1 is the source string and operand 2
-;; is a scratch register.
-
-(define_expand "movsd"
- [(parallel
- [(set (match_operand:BLK 0 "memory_operand" "")
- (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")]
- UNSPEC_STPCPY))
- (clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_operand 2 "register_operand" ""))])]
- "TARGET_H8300SX && 0"
- {
- operands[3] = copy_rtx (XEXP (operands[0], 0));
- operands[4] = copy_rtx (XEXP (operands[1], 0));
- })
-
-;; See comments above memcpy_internal().
-
-(define_insn "stpcpy_internal_<mode>"
- [(set (mem:BLK (match_operand:P 3 "register_operand" "0,r"))
- (unspec:BLK [(mem:BLK (match_operand:P 4 "register_operand" "1,1"))]
- UNSPEC_STPCPY))
- (clobber (match_operand:P 0 "register_operand" "=d,??D"))
- (clobber (match_operand:P 1 "register_operand" "=f,f"))
- (clobber (match_operand:P 2 "register_operand" "=c,c"))]
- "TARGET_H8300SX && 0"
- "@
- \n1:\tmovsd\t2f\;bra\t1b\n2:
- #"
- [(set_attr "length" "6,18")
- (set_attr "cc" "none,clobber")])
-
-;; Split the above instruction if the destination isn't er6. This works
-;; in the same way as the movmd splitter.
-
-(define_split
- [(set (match_operand:BLK 0 "memory_operand" "")
- (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY))
- (clobber (match_operand:P 2 "register_operand" ""))
- (clobber (match_operand:P 3 "register_operand" ""))
- (clobber (match_operand:P 4 "register_operand" ""))]
- "TARGET_H8300SX && reload_completed
- && 0
- && REGNO (operands[2]) != DESTINATION_REG"
- [(const_int 0)]
- {
- rtx dest;
-
- h8300_swap_into_er6 (XEXP (operands[0], 0));
- dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
- emit_insn (gen_movsd (dest, operands[1], operands[4]));
- h8300_swap_out_of_er6 (operands[2]);
- DONE;
- })
-
(include "mova.md")
(define_insn "*movsf_h8300"
(clobber (match_dup 2))])]
"")
-;; Convert a QImode push into an SImode push so that the
-;; define_peephole2 below can cram multiple pushes into one stm.l.
-
-(define_peephole2
- [(parallel [(set (reg:SI SP_REG)
- (plus:SI (reg:SI SP_REG) (const_int -4)))
- (set (mem:QI (plus:SI (reg:SI SP_REG) (const_int -3)))
- (match_operand:QI 0 "register_operand" ""))])]
- "TARGET_H8300S && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
- [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
- (match_dup 0))]
- {
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- })
-
-(define_peephole2
- [(parallel [(set (reg:HI SP_REG)
- (plus:HI (reg:HI SP_REG) (const_int -4)))
- (set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -3)))
- (match_operand:QI 0 "register_operand" ""))])]
- "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
- [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
- (match_dup 0))]
- {
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- })
-
-;; Convert a HImode push into an SImode push so that the
-;; define_peephole2 below can cram multiple pushes into one stm.l.
-
-(define_peephole2
- [(parallel [(set (reg:SI SP_REG)
- (plus:SI (reg:SI SP_REG) (const_int -4)))
- (set (mem:HI (plus:SI (reg:SI SP_REG) (const_int -2)))
- (match_operand:HI 0 "register_operand" ""))])]
- "TARGET_H8300S && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
- [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
- (match_dup 0))]
- {
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- })
-
-(define_peephole2
- [(parallel [(set (reg:HI SP_REG)
- (plus:HI (reg:HI SP_REG) (const_int -4)))
- (set (mem:HI (plus:HI (reg:HI SP_REG) (const_int -2)))
- (match_operand:HI 0 "register_operand" ""))])]
- "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
- [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
- (match_dup 0))]
- {
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- })
-
;; Cram four pushes into stm.l.
(define_peephole2
(match_dup 0))]
"")
-;; Transform
-;;
-;; mov dst,reg
-;; op src,reg
-;; mov reg,dst
-;;
-;; into
-;;
-;; op src,dst
-;;
-;; if "reg" dies at the end of the sequence.
-
-(define_peephole2
- [(set (match_operand 0 "register_operand" "")
- (match_operand 1 "memory_operand" ""))
- (set (match_dup 0)
- (match_operator 2 "h8sx_binary_memory_operator"
- [(match_dup 0)
- (match_operand 3 "h8300_src_operand" "")]))
- (set (match_operand 4 "memory_operand" "")
- (match_dup 0))]
- "0 /* Disable because it breaks compiling fp-bit.c. */
- && TARGET_H8300SX
- && peep2_reg_dead_p (3, operands[0])
- && !reg_overlap_mentioned_p (operands[0], operands[3])
- && !reg_overlap_mentioned_p (operands[0], operands[4])
- && h8sx_mergeable_memrefs_p (operands[4], operands[1])"
- [(set (match_dup 4)
- (match_dup 5))]
- {
- operands[5] = shallow_copy_rtx (operands[2]);
- XEXP (operands[5], 0) = operands[1];
- })
-
-;; Transform
-;;
-;; mov src,reg
-;; op reg,dst
-;;
-;; into
-;;
-;; op src,dst
-;;
-;; if "reg" dies in the second insn.
-
-(define_peephole2
- [(set (match_operand 0 "register_operand" "")
- (match_operand 1 "h8300_src_operand" ""))
- (set (match_operand 2 "h8300_dst_operand" "")
- (match_operator 3 "h8sx_binary_memory_operator"
- [(match_operand 4 "h8300_dst_operand" "")
- (match_dup 0)]))]
- "0 /* Disable because it breaks compiling fp-bit.c. */
- && TARGET_H8300SX
- && peep2_reg_dead_p (2, operands[0])
- && !reg_overlap_mentioned_p (operands[0], operands[4])"
- [(set (match_dup 2)
- (match_dup 5))]
- {
- operands[5] = shallow_copy_rtx (operands[3]);
- XEXP (operands[5], 1) = operands[1];
- })
-
;; Transform
;;
;; mov dst,reg