--- gcc/config/s390/predicates.md | 4 +++ gcc/config/s390/s390-protos.h | 1 + gcc/config/s390/s390.c | 16 ++++++++++++ gcc/config/s390/s390.md | 55 +++++++++++++++++++++++++++++++++++------ 4 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index 333457d..e4632b9 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -101,6 +101,10 @@ return true; }) +(define_predicate "nonzero_shift_count_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 1, GET_MODE_BITSIZE (mode) - 1)"))) + ;; Return true if OP a valid operand for the LARL instruction. (define_predicate "larl_operand" diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 79673d6..97c378f 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -110,5 +110,6 @@ extern bool s390_legitimate_address_without_index_p (rtx); extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *); extern int s390_branch_condition_mask (rtx); extern int s390_compare_and_branch_condition_mask (rtx); +extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT); #endif /* RTX_CODE */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 4e22100..52138d7 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -1308,6 +1308,22 @@ s390_contiguous_bitmask_p (unsigned HOST_WIDE_INT in, int size, return true; } +/* Check whether a rotate of ROTL followed by an AND of CONTIG is equivalent + to a shift followed by the AND. In particular, CONTIG should not overlap + the (rotated) bit 0/bit 63 gap. */ + +bool +s390_extzv_shift_ok (int bitsize, int rotl, unsigned HOST_WIDE_INT contig) +{ + int pos, len; + bool ok; + + ok = s390_contiguous_bitmask_p (contig, bitsize, &pos, &len); + gcc_assert (ok); + + return (rotl <= pos || rotl >= pos + len + (64 - bitsize)); +} + /* Check whether we can (and want to) split a double-word move in mode MODE from SRC to DST into two single-word moves, moving the subword FIRST_SUBWORD first. */ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index b6e1535..ae004ac 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -3298,15 +3298,25 @@ [(set_attr "op_type" "RS,RSY") (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) +(define_insn "extzv" + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extract:DI + (match_operand:DI 1 "register_operand" "d") + (match_operand 2 "const_int_operand" "") + (match_operand 3 "const_int_operand" ""))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10" + "risbg\t%0,%1,63-%3-%2,128+63,63-%3-%2" + [(set_attr "op_type" "RIE") + (set_attr "z10prop" "z10_super_E1")]) -(define_insn_and_split "*extzv<mode>" +(define_insn_and_split "*pre_z10_extzv<mode>" [(set (match_operand:GPR 0 "register_operand" "=d") (zero_extract:GPR (match_operand:QI 1 "s_operand" "QS") - (match_operand 2 "const_int_operand" "n") + (match_operand 2 "nonzero_shift_count_operand" "") (const_int 0))) (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" + "!TARGET_Z10" "#" "&& reload_completed" [(parallel @@ -3324,14 +3334,13 @@ operands[3] = GEN_INT (mask); }) -(define_insn_and_split "*extv<mode>" +(define_insn_and_split "*pre_z10_extv<mode>" [(set (match_operand:GPR 0 "register_operand" "=d") (sign_extract:GPR (match_operand:QI 1 "s_operand" "QS") - (match_operand 2 "const_int_operand" "n") + (match_operand 2 "nonzero_shift_count_operand" "") (const_int 0))) (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" + "!TARGET_Z10" "#" "&& reload_completed" [(parallel @@ -6034,6 +6043,36 @@ (clobber (reg:CC CC_REGNUM))])] "s390_narrow_logical_operator (AND, &operands[0], &operands[1]);") +;; These two are what combine generates for (ashift (zero_extract)). +(define_insn "*extzv_<mode>_srl" + [(set (match_operand:DSI 0 "register_operand" "=d") + (and:DSI (lshiftrt:DSI + (match_operand:DSI 1 "register_operand" "d") + (match_operand:DSI 2 "nonzero_shift_count_operand" "")) + (match_operand:DSI 3 "contiguous_bitmask_operand" ""))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 + /* Note that even for the SImode pattern, the rotate is always DImode. */ + && s390_extzv_shift_ok (<bitsize>, 64 - INTVAL (operands[2]), + INTVAL (operands[3]))" + "risbg\t%0,%1,%<bfstart>3,128+%<bfend>3,64-%2" + [(set_attr "op_type" "RIE") + (set_attr "z10prop" "z10_super_E1")]) + +(define_insn "*extzv_<mode>_sll" + [(set (match_operand:DSI 0 "register_operand" "=d") + (and:DSI (ashift:DSI + (match_operand:DSI 1 "register_operand" "d") + (match_operand:DSI 2 "nonzero_shift_count_operand" "")) + (match_operand:DSI 3 "contiguous_bitmask_operand" ""))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 + && s390_extzv_shift_ok (<bitsize>, INTVAL (operands[2]), + INTVAL (operands[3]))" + "risbg\t%0,%1,%<bfstart>3,128+%<bfend>3,%2" + [(set_attr "op_type" "RIE") + (set_attr "z10prop" "z10_super_E1")]) + ; ; andsi3 instruction pattern(s). -- 1.7.7.6