diff options
author | Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> | 2023-05-16 08:34:22 +0200 |
---|---|---|
committer | Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> | 2023-05-16 08:34:22 +0200 |
commit | 5154171e1f3aa4aa120cee3ecf0347cd72a427fb (patch) | |
tree | 78d15c071c4ed48dbabd4baf8cc74b64b927d0b3 | |
parent | 0cc6d0e7e248014d00a38a27e92ed58dbe2b0469 (diff) | |
download | gcc-5154171e1f3aa4aa120cee3ecf0347cd72a427fb.tar.gz |
s390: Add block operation movmem
gcc/ChangeLog:
* config/s390/s390-protos.h (s390_expand_movmem): New.
* config/s390/s390.cc (s390_expand_movmem): New.
* config/s390/s390.md (movmem<mode>): New.
(*mvcrl): New.
(mvcrl): New.
-rw-r--r-- | gcc/config/s390/s390-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/s390/s390.cc | 88 | ||||
-rw-r--r-- | gcc/config/s390/s390.md | 35 |
3 files changed, 124 insertions, 0 deletions
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 2c7495ca247..65e4f97b41e 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -108,6 +108,7 @@ extern void s390_expand_plus_operand (rtx, rtx, rtx); extern void emit_symbolic_move (rtx *); extern void s390_load_address (rtx, rtx); extern bool s390_expand_cpymem (rtx, rtx, rtx, rtx, rtx); +extern bool s390_expand_movmem (rtx, rtx, rtx, rtx, rtx); extern void s390_expand_setmem (rtx, rtx, rtx); extern bool s390_expand_cmpmem (rtx, rtx, rtx, rtx); extern void s390_expand_vec_strlen (rtx, rtx, rtx); diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 95ea5e8d009..553273f23ff 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -5818,6 +5818,94 @@ s390_expand_cpymem (rtx dst, rtx src, rtx len, rtx min_len_rtx, rtx max_len_rtx) return false; } +bool +s390_expand_movmem (rtx dst, rtx src, rtx len, rtx min_len_rtx, rtx max_len_rtx) +{ + /* Exit early in case nothing has to be done. */ + if (CONST_INT_P (len) && UINTVAL (len) == 0) + return true; + /* Exit early in case length is not upper bounded. */ + else if (max_len_rtx == NULL) + return false; + + unsigned HOST_WIDE_INT min_len = UINTVAL (min_len_rtx); + unsigned HOST_WIDE_INT max_len = UINTVAL (max_len_rtx); + + /* At most 16 bytes. */ + if (max_len <= 16 && TARGET_VX) + { + rtx_code_label *end_label; + + if (min_len == 0) + { + end_label = gen_label_rtx (); + emit_cmp_and_jump_insns (len, const0_rtx, EQ, NULL_RTX, + GET_MODE (len), 1, end_label, + profile_probability::very_unlikely ()); + } + + rtx lenm1; + if (CONST_INT_P (len)) + { + lenm1 = gen_reg_rtx (SImode); + emit_move_insn (lenm1, GEN_INT (UINTVAL (len) - 1)); + } + else + lenm1 + = expand_binop (SImode, add_optab, convert_to_mode (SImode, len, 1), + constm1_rtx, NULL_RTX, 1, OPTAB_DIRECT); + + rtx tmp = gen_reg_rtx (V16QImode); + emit_insn (gen_vllv16qi (tmp, lenm1, src)); + emit_insn (gen_vstlv16qi (tmp, lenm1, dst)); + + if (min_len == 0) + emit_label (end_label); + + return true; + } + + /* At most 256 bytes. */ + else if (max_len <= 256 && TARGET_Z15) + { + rtx_code_label *end_label = gen_label_rtx (); + + if (min_len == 0) + emit_cmp_and_jump_insns (len, const0_rtx, EQ, NULL_RTX, GET_MODE (len), + 1, end_label, + profile_probability::very_unlikely ()); + + rtx dst_addr = gen_reg_rtx (Pmode); + rtx src_addr = gen_reg_rtx (Pmode); + emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX)); + emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX)); + + rtx lenm1 = CONST_INT_P (len) + ? GEN_INT (UINTVAL (len) - 1) + : expand_binop (GET_MODE (len), add_optab, len, constm1_rtx, + NULL_RTX, 1, OPTAB_DIRECT); + + rtx_code_label *right_to_left_label = gen_label_rtx (); + emit_cmp_and_jump_insns (src_addr, dst_addr, LT, NULL_RTX, GET_MODE (len), + 1, right_to_left_label); + + // MVC + emit_insn ( + gen_cpymem_short (dst, src, convert_to_mode (Pmode, lenm1, 1))); + emit_jump (end_label); + + // MVCRL + emit_label (right_to_left_label); + emit_insn (gen_mvcrl (dst, src, convert_to_mode (SImode, lenm1, 1))); + + emit_label (end_label); + + return true; + } + + return false; +} + /* Emit code to set LEN bytes at DST to VAL. Make use of clrmem if VAL is zero. */ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index d9ce287ab85..abe3bbc5cd9 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -61,6 +61,7 @@ UNSPEC_ROUND UNSPEC_ICM UNSPEC_TIE + UNSPEC_MVCRL ; Convert CC into a str comparison result and copy it into an ; integer register @@ -3496,6 +3497,40 @@ [(set_attr "length" "8") (set_attr "type" "vs")]) +(define_expand "movmem<mode>" + [(set (match_operand:BLK 0 "memory_operand") ; destination + (match_operand:BLK 1 "memory_operand")) ; source + (use (match_operand:GPR 2 "general_operand")) ; size + (match_operand 3 "") ; align + (match_operand 4 "") ; expected align + (match_operand 5 "") ; expected size + (match_operand 6 "") ; minimal size + (match_operand 7 "")] ; maximal size + "" +{ + if (s390_expand_movmem (operands[0], operands[1], operands[2], operands[6], operands[7])) + DONE; + else + FAIL; +}) + +(define_insn "*mvcrl" + [(set (match_operand:BLK 0 "memory_operand" "=Q") + (unspec:BLK [(match_operand:BLK 1 "memory_operand" "Q") + (reg:SI GPR0_REGNUM)] + UNSPEC_MVCRL))] + "TARGET_Z15" + "mvcrl\t%0,%1" + [(set_attr "op_type" "SSE")]) + +(define_expand "mvcrl" + [(set (reg:SI GPR0_REGNUM) (match_operand:SI 2 "general_operand")) + (set (match_operand:BLK 0 "memory_operand" "=Q") + (unspec:BLK [(match_operand:BLK 1 "memory_operand" "Q") + (reg:SI GPR0_REGNUM)] + UNSPEC_MVCRL))] + "TARGET_Z15" + "") ; ; Test data class. |