I've changed the s390_extzv_shift_ok function and have added extzv patterns for zEC12. I also tried to implement an extzvsi expander but ran into some issues which need to be fixed first.
Tested on s390 and s390x with z196 and zEC12. Please apply to mainline. Thanks! Bye, -Andreas- gcc/config/s390/predicates.md | 4 + gcc/config/s390/s390-protos.h | 1 gcc/config/s390/s390.c | 18 ++++++++ gcc/config/s390/s390.md | 94 +++++++++++++++++++++++++!!!!!!!!!!!!!!!!! 4 files changed, 81 insertions(+), 36 modifications(!) Index: gcc/config/s390/predicates.md =================================================================== *** gcc/config/s390/predicates.md.orig --- gcc/config/s390/predicates.md *************** *** 101,106 **** --- 101,110 ---- 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" Index: gcc/config/s390/s390-protos.h =================================================================== *** gcc/config/s390/s390-protos.h.orig --- gcc/config/s390/s390-protos.h *************** extern bool s390_legitimate_address_with *** 109,113 **** --- 109,114 ---- 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 */ Index: gcc/config/s390/s390.c =================================================================== *** gcc/config/s390/s390.c.orig --- gcc/config/s390/s390.c *************** s390_contiguous_bitmask_p (unsigned HOST *** 1347,1352 **** --- 1347,1370 ---- 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. Negative values + for ROTL indicate a rotate to the right. */ + + 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 >= 0 && rotl <= pos) + || (rotl < 0 && -rotl <= bitsize - len - pos)); + } + /* 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. */ Index: gcc/config/s390/s390.md =================================================================== *** gcc/config/s390/s390.md.orig --- gcc/config/s390/s390.md *************** *** 3307,3321 **** [(set_attr "op_type" "RS,RSY") (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) ! (define_insn_and_split "*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") (const_int 0))) (clobber (reg:CC CC_REGNUM))] ! "INTVAL (operands[2]) > 0 ! && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" "#" "&& reload_completed" [(parallel --- 3307,3370 ---- [(set_attr "op_type" "RS,RSY") (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) + ; + ; extv instruction patterns + ; + + ; FIXME: This expander needs to be converted from DI to GPR as well + ; after resolving some issues with it. + + (define_expand "extzv" + [(parallel + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extract:DI + (match_operand:DI 1 "register_operand" "d") + (match_operand 2 "const_int_operand" "") ; size + (match_operand 3 "const_int_operand" ""))) ; start + (clobber (reg:CC CC_REGNUM))])] + "TARGET_Z10" + { + /* Starting with zEC12 there is risbgn not clobbering CC. */ + if (TARGET_ZEC12) + { + emit_move_insn (operands[0], + gen_rtx_ZERO_EXTRACT (DImode, + operands[1], + operands[2], + operands[3])); + DONE; + } + }) ! (define_insn "*extzv<mode>_zEC12" ! [(set (match_operand:GPR 0 "register_operand" "=d") ! (zero_extract:GPR ! (match_operand:GPR 1 "register_operand" "d") ! (match_operand 2 "const_int_operand" "") ; size ! (match_operand 3 "const_int_operand" "")))] ; start] ! "TARGET_ZEC12" ! "risbgn\t%0,%1,64-%2,128+63,<bitsize>+%3+%2" ; dst, src, start, end, shift ! [(set_attr "op_type" "RIE")]) ! ! (define_insn "*extzv<mode>_z10" ! [(set (match_operand:GPR 0 "register_operand" "=d") ! (zero_extract:GPR ! (match_operand:GPR 1 "register_operand" "d") ! (match_operand 2 "const_int_operand" "") ; size ! (match_operand 3 "const_int_operand" ""))) ; start ! (clobber (reg:CC CC_REGNUM))] ! "TARGET_Z10" ! "risbg\t%0,%1,64-%2,128+63,<bitsize>+%3+%2" ; dst, src, start, end, shift ! [(set_attr "op_type" "RIE") ! (set_attr "z10prop" "z10_super_E1")]) ! ! (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 "nonzero_shift_count_operand" "") (const_int 0))) (clobber (reg:CC CC_REGNUM))] ! "!TARGET_Z10" "#" "&& reload_completed" [(parallel *************** *** 3333,3346 **** operands[3] = GEN_INT (mask); }) ! (define_insn_and_split "*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") (const_int 0))) (clobber (reg:CC CC_REGNUM))] ! "INTVAL (operands[2]) > 0 ! && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" "#" "&& reload_completed" [(parallel --- 3382,3394 ---- operands[3] = GEN_INT (mask); }) ! (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 "nonzero_shift_count_operand" "") (const_int 0))) (clobber (reg:CC CC_REGNUM))] ! "" "#" "&& reload_completed" [(parallel *************** *** 6067,6072 **** --- 6115,6150 ---- (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:GPR 0 "register_operand" "=d") + (and:GPR (lshiftrt:GPR + (match_operand:GPR 1 "register_operand" "d") + (match_operand:GPR 2 "nonzero_shift_count_operand" "")) + (match_operand:GPR 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>, -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:GPR 0 "register_operand" "=d") + (and:GPR (ashift:GPR + (match_operand:GPR 1 "register_operand" "d") + (match_operand:GPR 2 "nonzero_shift_count_operand" "")) + (match_operand:GPR 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).