Try RISBG last, after other mechanisms have failed; don't require operands in registers for it but force them there instead. Try a limited form of ICM. --- gcc/config/s390/s390.c | 129 ++++++++++++++++++++++++++++++----------------- 1 files changed, 82 insertions(+), 47 deletions(-)
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index f72f49f..240fb7e 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -4538,48 +4538,70 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) { int bitsize = INTVAL (op1); int bitpos = INTVAL (op2); + enum machine_mode mode = GET_MODE (dest); + enum machine_mode smode = smallest_mode_for_size (bitsize, MODE_INT); + rtx op, clobber; - /* On z10 we can use the risbg instruction to implement insv. */ - if (TARGET_Z10 - && ((GET_MODE (dest) == DImode && GET_MODE (src) == DImode) - || (GET_MODE (dest) == SImode && GET_MODE (src) == SImode))) + /* Generate INSERT IMMEDIATE (IILL et al). */ + /* (set (ze (reg)) (const_int)). */ + if (TARGET_ZARCH + && register_operand (dest, word_mode) + && (bitpos % 16) == 0 + && (bitsize % 16) == 0 + && const_int_operand (src, VOIDmode)) { - rtx op; - rtx clobber; + HOST_WIDE_INT val = INTVAL (src); + int regpos = bitpos + bitsize; - op = gen_rtx_SET (GET_MODE(src), - gen_rtx_ZERO_EXTRACT (GET_MODE (dest), dest, op1, op2), - src); - clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber))); + while (regpos > bitpos) + { + enum machine_mode putmode; + int putsize; + + if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32)) + putmode = SImode; + else + putmode = HImode; + putsize = GET_MODE_BITSIZE (putmode); + regpos -= putsize; + emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, + GEN_INT (putsize), + GEN_INT (regpos)), + gen_int_mode (val, putmode)); + val >>= putsize; + } + gcc_assert (regpos == bitpos); return true; } - /* We need byte alignment. */ - if (bitsize % BITS_PER_UNIT) - return false; - + /* Generate STORE CHARACTERS UNDER MASK (STCM et al). */ if (bitpos == 0 - && memory_operand (dest, VOIDmode) + && (bitsize % BITS_PER_UNIT) == 0 + && MEM_P (dest) && (register_operand (src, word_mode) || const_int_operand (src, VOIDmode))) { /* Emit standard pattern if possible. */ - enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT); - if (GET_MODE_BITSIZE (mode) == bitsize) - emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src)); + if (GET_MODE_BITSIZE (smode) == bitsize) + { + emit_move_insn (adjust_address (dest, smode, 0), + gen_lowpart (smode, src)); + return true; + } /* (set (ze (mem)) (const_int)). */ else if (const_int_operand (src, VOIDmode)) { int size = bitsize / BITS_PER_UNIT; - rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode, + rtx src_mem = adjust_address (force_const_mem (word_mode, src), + BLKmode, GET_MODE_SIZE (word_mode) - size); dest = adjust_address (dest, BLKmode, 0); set_mem_size (dest, size); s390_expand_movmem (dest, src_mem, GEN_INT (size)); + return true; } /* (set (ze (mem)) (reg)). */ @@ -4602,42 +4624,55 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) gen_rtx_LSHIFTRT (word_mode, src, GEN_INT (GET_MODE_BITSIZE (SImode)))); } + return true; } - else - return false; + } - return true; + /* Generate INSERT CHARACTERS UNDER MASK (IC, ICM et al). */ + if ((bitpos % BITS_PER_UNIT) == 0 + && (bitsize % BITS_PER_UNIT) == 0 + && (bitpos & 32) == ((bitpos + bitsize - 1) & 32) + && MEM_P (src) + && (mode == DImode || mode == SImode) + && register_operand (dest, mode)) + { + /* Emit a strict_low_part pattern if possible. */ + if (bitpos == 0 && GET_MODE_BITSIZE (smode) == bitsize) + { + op = gen_rtx_STRICT_LOW_PART (VOIDmode, gen_lowpart (smode, dest)); + op = gen_rtx_SET (VOIDmode, op, gen_lowpart (smode, src)); + clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber))); + return true; + } + + /* ??? There are more powerful versions of ICM that are not + completely represented in the md file. */ } - /* (set (ze (reg)) (const_int)). */ - if (TARGET_ZARCH - && register_operand (dest, word_mode) - && (bitpos % 16) == 0 - && (bitsize % 16) == 0 - && const_int_operand (src, VOIDmode)) + /* For z10, generate ROTATE THEN INSERT SELECTED BITS (RISBG et al). */ + if (TARGET_Z10 && (mode == DImode || mode == SImode)) { - HOST_WIDE_INT val = INTVAL (src); - int regpos = bitpos + bitsize; + enum machine_mode mode_s = GET_MODE (src); - while (regpos > bitpos) + if (mode_s == VOIDmode) { - enum machine_mode putmode; - int putsize; + /* Assume const_int etc already in the proper mode. */ + src = force_reg (mode, src); + } + else if (mode_s != mode) + { + gcc_assert (GET_MODE_BITSIZE (mode_s) >= bitsize); + src = force_reg (mode_s, src); + src = gen_lowpart (mode, src); + } - if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32)) - putmode = SImode; - else - putmode = HImode; + op = gen_rtx_SET (mode, + gen_rtx_ZERO_EXTRACT (mode, dest, op1, op2), + src); + clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber))); - putsize = GET_MODE_BITSIZE (putmode); - regpos -= putsize; - emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, - GEN_INT (putsize), - GEN_INT (regpos)), - gen_int_mode (val, putmode)); - val >>= putsize; - } - gcc_assert (regpos == bitpos); return true; } -- 1.7.7.6