diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 139c6174be7b..feb6a71ab21f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2005-10-19 Adrian Straetling + + * config/s390/s390.c (s390_expand_insv): New. + * config/s390/s390-protos.h (s390_expand_insv): Declare. + * config/s390/s390.md ("UNSPEC_SETHIGH"): Rename to "UNSPEC_ICM". + ("icm_hi"): Remove mode attribute. + ("*sethigh"): Rewrite to "sethighpart". + Adjust all uses. + ("*extracthi", "*extractqi"): Remove. + (extv", "*extzv"): New. + ("insv", "*insv_mem_reg", "*insvdi_mem_reghigh", + "*insv_reg_imm", "*insv_reg_extimm"): New. + 2005-10-19 Ulrich Weigand * cfgexpand.c (discover_nonconstant_array_refs_r, diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index b18e1d13f07b..3ae43ea209ea 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -74,6 +74,7 @@ extern void s390_expand_movmem (rtx, rtx, rtx); extern void s390_expand_setmem (rtx, rtx, rtx); extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx); extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx); +extern bool s390_expand_insv (rtx, rtx, rtx, rtx); extern rtx s390_return_addr_rtx (int, rtx); extern rtx s390_back_chain_rtx (void); extern rtx s390_emit_call (rtx, rtx, rtx, rtx); diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 445f4e1a10de..009c17828d89 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -3815,6 +3815,101 @@ s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1, return false; } +/* Expand code for the insv template. Return true if successful, false else. */ + +bool +s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) +{ + int bitsize = INTVAL (op1); + int bitpos = INTVAL (op2); + + /* We need byte alignement. */ + if (bitsize % BITS_PER_UNIT) + return false; + + if (bitpos == 0 + && memory_operand (dest, VOIDmode) + && (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)); + + /* (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, + GET_MODE_SIZE (word_mode) - size); + + dest = adjust_address (dest, BLKmode, 0); + set_mem_size (dest, GEN_INT (size)); + s390_expand_movmem (dest, src_mem, GEN_INT (size)); + } + + /* (set (ze (mem)) (reg)). */ + else if (register_operand (src, word_mode)) + { + if (bitsize <= GET_MODE_BITSIZE (SImode)) + emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1, + const0_rtx), src); + else + { + /* Emit st,stcmh sequence. */ + int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode); + int size = stcmh_width / BITS_PER_UNIT; + + emit_move_insn (adjust_address (dest, SImode, size), + gen_lowpart (SImode, src)); + set_mem_size (dest, GEN_INT (size)); + emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT + (stcmh_width), const0_rtx), + gen_rtx_LSHIFTRT (word_mode, src, GEN_INT + (GET_MODE_BITSIZE (SImode)))); + } + } + else + return false; + + return true; + } + + /* (set (ze (reg)) (const_int)). */ + if (TARGET_ZARCH + && register_operand (dest, word_mode) + && (bitpos % 16) == 0 + && (bitsize % 16) == 0 + && const_int_operand (src, VOIDmode)) + { + HOST_WIDE_INT val = INTVAL (src); + int regpos = bitpos + bitsize; + + 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; + } + + return false; +} /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. We need to emit DTP-relative relocations. */ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index baea3ff42e16..bc9e4c362629 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -102,7 +102,7 @@ [; Miscellaneous (UNSPEC_ROUND 1) (UNSPEC_CMPINT 2) - (UNSPEC_SETHIGH 10) + (UNSPEC_ICM 10) ; GOT/PLT and lt-relative accesses (UNSPEC_LTREL_OFFSET 100) @@ -352,10 +352,6 @@ ;; and "cfdbr" in SImode. (define_mode_attr gf [(DI "g") (SI "f")]) -;; ICM mask required to load MODE value into the highest subreg -;; of a SImode register. -(define_mode_attr icm_hi [(HI "12") (QI "8")]) - ;; ICM mask required to load MODE value into the lowest subreg ;; of a SImode register. (define_mode_attr icm_lo [(HI "3") (QI "1")]) @@ -2464,73 +2460,180 @@ ;;- Conversion instructions. ;; - -(define_insn "*sethighsi" +(define_insn "*sethighpartsi" [(set (match_operand:SI 0 "register_operand" "=d,d") - (unspec:SI [(match_operand:HQI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH)) + (unspec:SI [(match_operand:BLK 1 "s_operand" "Q,S") + (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))] "" "@ - icm\t%0,,%S1 - icmy\t%0,,%S1" + icm\t%0,%2,%S1 + icmy\t%0,%2,%S1" [(set_attr "op_type" "RS,RSY")]) -(define_insn "*sethighqidi_64" +(define_insn "*sethighpartdi_64" [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:QI 1 "s_operand" "QS")] UNSPEC_SETHIGH)) + (unspec:DI [(match_operand:BLK 1 "s_operand" "QS") + (match_operand 2 "const_int_operand" "n")] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))] "TARGET_64BIT" - "icmh\t%0,8,%S1" + "icmh\t%0,%2,%S1" [(set_attr "op_type" "RSY")]) -(define_insn "*sethighqidi_31" +(define_insn "*sethighpartdi_31" [(set (match_operand:DI 0 "register_operand" "=d,d") - (unspec:DI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH)) + (unspec:DI [(match_operand:BLK 1 "s_operand" "Q,S") + (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))] "!TARGET_64BIT" "@ - icm\t%0,8,%S1 - icmy\t%0,8,%S1" + icm\t%0,%2,%S1 + icmy\t%0,%2,%S1" [(set_attr "op_type" "RS,RSY")]) -(define_insn_and_split "*extractqi" - [(set (match_operand:SI 0 "register_operand" "=d") - (zero_extract:SI (match_operand:QI 1 "s_operand" "Q") - (match_operand 2 "const_int_operand" "n") - (const_int 0))) +(define_insn_and_split "*extzv" + [(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))] - "!TARGET_64BIT - && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8" + "INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) + [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))]) - (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] + (set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))] { - operands[2] = GEN_INT (32 - INTVAL (operands[2])); - operands[1] = change_address (operands[1], QImode, 0); + int bitsize = INTVAL (operands[2]); + int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */ + int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size); + + operands[1] = adjust_address (operands[1], BLKmode, 0); + set_mem_size (operands[1], GEN_INT (size)); + operands[2] = GEN_INT (GET_MODE_BITSIZE (mode) - bitsize); + operands[3] = GEN_INT (mask); }) -(define_insn_and_split "*extracthi" - [(set (match_operand:SI 0 "register_operand" "=d") - (zero_extract:SI (match_operand:QI 1 "s_operand" "Q") - (match_operand 2 "const_int_operand" "n") - (const_int 0))) +(define_insn_and_split "*extv" + [(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))] - "!TARGET_64BIT - && INTVAL (operands[2]) >= 8 && INTVAL (operands[2]) < 16" + "INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) + [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))]) - (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] + (parallel + [(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] { - operands[2] = GEN_INT (32 - INTVAL (operands[2])); - operands[1] = change_address (operands[1], HImode, 0); + int bitsize = INTVAL (operands[2]); + int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */ + int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size); + + operands[1] = adjust_address (operands[1], BLKmode, 0); + set_mem_size (operands[1], GEN_INT (size)); + operands[2] = GEN_INT (GET_MODE_BITSIZE (mode) - bitsize); + operands[3] = GEN_INT (mask); }) +; +; insv instruction patterns +; + +(define_expand "insv" + [(set (zero_extract (match_operand 0 "nonimmediate_operand" "") + (match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" "")) + (match_operand 3 "general_operand" ""))] + "" +{ + if (s390_expand_insv (operands[0], operands[1], operands[2], operands[3])) + DONE; + FAIL; +}) + +(define_insn "*insv_mem_reg" + [(set (zero_extract:P (match_operand:QI 0 "memory_operand" "+Q,S") + (match_operand 1 "const_int_operand" "n,n") + (const_int 0)) + (match_operand:P 2 "register_operand" "d,d"))] + "INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode) + && INTVAL (operands[1]) % BITS_PER_UNIT == 0" +{ + int size = INTVAL (operands[1]) / BITS_PER_UNIT; + + operands[1] = GEN_INT ((1ul << size) - 1); + return (which_alternative == 0) ? "stcm\t%2,%1,%S0" + : "stcmy\t%2,%1,%S0"; +} + [(set_attr "op_type" "RS,RSY")]) + +(define_insn "*insvdi_mem_reghigh" + [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "+QS") + (match_operand 1 "const_int_operand" "n") + (const_int 0)) + (lshiftrt:DI (match_operand:DI 2 "register_operand" "d") + (const_int 32)))] + "TARGET_64BIT + && INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode) + && INTVAL (operands[1]) % BITS_PER_UNIT == 0" +{ + int size = INTVAL (operands[1]) / BITS_PER_UNIT; + + operands[1] = GEN_INT ((1ul << size) - 1); + return "stcmh\t%2,%1,%S0"; +} +[(set_attr "op_type" "RSY")]) + +(define_insn "*insv_reg_imm" + [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d") + (const_int 16) + (match_operand 1 "const_int_operand" "n")) + (match_operand:P 2 "const_int_operand" "K"))] + "TARGET_ZARCH + && INTVAL (operands[1]) >= 0 + && INTVAL (operands[1]) < BITS_PER_WORD + && INTVAL (operands[1]) % 16 == 0" +{ + switch (BITS_PER_WORD - INTVAL (operands[1])) + { + case 64: return "iihh\t%0,%x2"; break; + case 48: return "iihl\t%0,%x2"; break; + case 32: return "iilh\t%0,%x2"; break; + case 16: return "iill\t%0,%x2"; break; + default: gcc_unreachable(); + } +} + [(set_attr "op_type" "RI")]) + +(define_insn "*insv_reg_extimm" + [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d") + (const_int 32) + (match_operand 1 "const_int_operand" "n")) + (match_operand:P 2 "const_int_operand" "Os"))] + "TARGET_EXTIMM + && INTVAL (operands[1]) >= 0 + && INTVAL (operands[1]) < BITS_PER_WORD + && INTVAL (operands[1]) % 32 == 0" +{ + switch (BITS_PER_WORD - INTVAL (operands[1])) + { + case 64: return "iihf\t%0,%o2"; break; + case 32: return "iilf\t%0,%o2"; break; + default: gcc_unreachable(); + } +} + [(set_attr "op_type" "RIL")]) + ; ; extendsidi2 instruction pattern(s). ; @@ -2626,12 +2729,15 @@ "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_SETHIGH)) + [(set (match_dup 0) (unspec:DI [(match_dup 1) (const_int 8)] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))]) (parallel [(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 56))) (clobber (reg:CC CC_REGNUM))])] - "") +{ + operands[1] = adjust_address (operands[1], BLKmode, 0); + set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode))); +}) ; ; extend(hi|qi)si2 instruction pattern(s). @@ -2696,12 +2802,15 @@ "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) + [(set (match_dup 0) (unspec:SI [(match_dup 1) (const_int 8)] UNSPEC_ICM)) (clobber (reg:CC CC_REGNUM))]) (parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 24))) (clobber (reg:CC CC_REGNUM))])] - "") +{ + operands[1] = adjust_address (operands[1], BLKmode, 0); + set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode))); +}) ; ; extendqihi2 instruction pattern(s).