}
}
-/* Emit code to clear LEN bytes at DST. */
+/* Emit code to set LEN bytes at DST to VAL.
+ Make use of clrmem if VAL is zero. */
void
-s390_expand_clrmem (rtx dst, rtx len)
+s390_expand_setmem (rtx dst, rtx len, rtx val)
{
- if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
+ gcc_assert (GET_CODE (len) != CONST_INT || INTVAL (len) > 0);
+ gcc_assert (GET_CODE (val) == CONST_INT || GET_MODE (val) == QImode);
+
+ if (GET_CODE (len) == CONST_INT && INTVAL (len) <= 257)
{
- if (INTVAL (len) > 0)
+ if (val == const0_rtx && INTVAL (len) <= 256)
emit_insn (gen_clrmem_short (dst, GEN_INT (INTVAL (len) - 1)));
+ else
+ {
+ /* Initialize memory by storing the first byte. */
+ emit_move_insn (adjust_address (dst, QImode, 0), val);
+
+ if (INTVAL (len) > 1)
+ {
+ /* Initiate 1 byte overlap move.
+ The first byte of DST is propagated through DSTP1.
+ Prepare a movmem for: DST+1 = DST (length = LEN - 1).
+ DST is set to size 1 so the rest of the memory location
+ does not count as source operand. */
+ rtx dstp1 = adjust_address (dst, VOIDmode, 1);
+ set_mem_size (dst, const1_rtx);
+
+ emit_insn (gen_movmem_short (dstp1, dst,
+ GEN_INT (INTVAL (len) - 2)));
+ }
+ }
}
else if (TARGET_MVCLE)
{
- emit_insn (gen_clrmem_long (dst, convert_to_mode (Pmode, len, 1)));
+ val = force_not_mem (convert_modes (Pmode, QImode, val, 1));
+ emit_insn (gen_setmem_long (dst, convert_to_mode (Pmode, len, 1), val));
}
else
{
- rtx dst_addr, src_addr, count, blocks, temp;
+ rtx dst_addr, src_addr, count, blocks, temp, dstp1 = NULL_RTX;
rtx loop_start_label = gen_label_rtx ();
rtx loop_end_label = gen_label_rtx ();
rtx end_label = gen_label_rtx ();
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
dst = change_address (dst, VOIDmode, dst_addr);
- temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ if (val == const0_rtx)
+ temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ else
+ {
+ dstp1 = adjust_address (dst, VOIDmode, 1);
+ set_mem_size (dst, const1_rtx);
+
+ /* Initialize memory by storing the first byte. */
+ emit_move_insn (adjust_address (dst, QImode, 0), val);
+
+ /* If count is 1 we are done. */
+ emit_cmp_and_jump_insns (count, const1_rtx,
+ EQ, NULL_RTX, mode, 1, end_label);
+
+ temp = expand_binop (mode, add_optab, count, GEN_INT (-2), count, 1, 0);
+ }
if (temp != count)
emit_move_insn (count, temp);
emit_label (loop_start_label);
- emit_insn (gen_clrmem_short (dst, GEN_INT (255)));
+ if (val == const0_rtx)
+ emit_insn (gen_clrmem_short (dst, GEN_INT (255)));
+ else
+ emit_insn (gen_movmem_short (dstp1, dst, GEN_INT (255)));
s390_load_address (dst_addr,
gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
emit_jump (loop_start_label);
emit_label (loop_end_label);
- emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1)));
+ if (val == const0_rtx)
+ emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1)));
+ else
+ emit_insn (gen_movmem_short (dstp1, dst, convert_to_mode (Pmode, count, 1)));
emit_label (end_label);
}
}
return orig_x;
}
-/* Output shift count operand OP to stdio stream FILE. */
+/* Output operand OP to stdio stream FILE.
+ OP is an address (register + offset) which is not used to address data;
+ instead the rightmost bits are interpreted as the value. */
static void
print_shift_count_operand (FILE *file, rtx op)
gcc_assert (REGNO_REG_CLASS (REGNO (op)) == ADDR_REGS);
}
- /* Shift counts are truncated to the low six bits anyway. */
- fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & 63);
+ /* Offsets are constricted to twelve bits. */
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1));
if (op)
fprintf (file, "(%s)", reg_names[REGNO (op)]);
}
(define_expand "setmem<mode>"
[(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand 2 "const_int_operand" ""))
+ (match_operand:QI 2 "general_operand" ""))
(use (match_operand:GPR 1 "general_operand" ""))
(match_operand 3 "" "")]
""
-{
- /* If value to set is not zero, use the library routine. */
- if (operands[2] != const0_rtx)
- FAIL;
-
- s390_expand_clrmem (operands[0], operands[1]);
- DONE;
-})
+ "s390_expand_setmem (operands[0], operands[1], operands[2]); DONE;")
; Clear a block that is up to 256 bytes in length.
; The block length is taken as (operands[1] % 256) + 1.
(clobber (reg:CC CC_REGNUM))])]
"operands[3] = gen_label_rtx ();")
-; Clear a block of arbitrary length.
+; Initialize a block of arbitrary length with (operands[2] % 256).
-(define_expand "clrmem_long"
+(define_expand "setmem_long"
[(parallel
[(clobber (match_dup 1))
(set (match_operand:BLK 0 "memory_operand" "")
- (const_int 0))
+ (match_operand 2 "shift_count_operand" ""))
(use (match_operand 1 "general_operand" ""))
- (use (match_dup 2))
+ (use (match_dup 3))
(clobber (reg:CC CC_REGNUM))])]
""
{
operands[0] = replace_equiv_address_nv (operands[0], addr0);
operands[1] = reg0;
- operands[2] = reg1;
+ operands[3] = reg1;
})
-(define_insn "*clrmem_long"
+(define_insn "*setmem_long"
[(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
- (set (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0))
- (const_int 0))
- (use (match_dup 2))
+ (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0))
+ (match_operand 2 "shift_count_operand" "Y"))
+ (use (match_dup 3))
(use (match_operand:<DBL> 1 "register_operand" "d"))
(clobber (reg:CC CC_REGNUM))]
""
- "mvcle\t%0,%1,0\;jo\t.-4"
+ "mvcle\t%0,%1,%Y2\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])