From d2eeb2d179a4353af0a8ff989222301c4f7dc11b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 18 Nov 2012 17:34:06 +0000 Subject: [PATCH] gcc/ * doc/md.texi (extv@var{m}, extvmisalign@var{m}, extzv@var{m}) (extzvmisalign@var{m}, insv@var{m}, insvmisalign@var{m}): Document. (insv, extv, extzv): Deprecate. * optabs.def (insv_optab, extv_optab, extzv_optab) (insvmisalign_optab, extvmisalign_optab, extzvmisalign_optab): New optabs. * optabs.c (get_optab_extraction_insn): New function. (get_extraction_insn): Use it. * config/mips/mips.md (extv): Split into... (extvmisalign, extv): ...these new patterns. Rename existing extv pattern to... (*extv): ...this. (extzv): Split into... (extzvmisalign, extzv): ...these new patterns. Rename existing extzv pattern to... (*extzv): ...this. (insv): Split into... (insvmisalign, insv): ...these new patterns. Rename existing insv pattern to... (*insv): ...this. Use const_int_operand rather than immediate_operand. * config/mips/mips.c (mips_block_move_straight): Use set_mem_size to set the size of BLKmode accesses. (mips_get_unaligned_mem): Require OP0 to be a BLKmode memory, turning it from an "rtx *" to an rtx. (mips_expand_ext_as_unaligned_load): Simplify for new optab interface. Update call to mips_get_unaligned_mem. (mips_expand_ins_as_unaligned_store): Update call to mips_get_unaligned_mem. From-SVN: r193606 --- gcc/ChangeLog | 32 +++++++++++ gcc/config/mips/mips.c | 48 ++++------------- gcc/config/mips/mips.md | 115 ++++++++++++++++++++-------------------- gcc/doc/md.texi | 65 +++++++++++++++++++++++ gcc/optabs.c | 38 +++++++++++-- gcc/optabs.def | 6 +++ 6 files changed, 207 insertions(+), 97 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9361e357aea..d155a39f736 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +2012-11-18 Richard Sandiford + + * doc/md.texi (extv@var{m}, extvmisalign@var{m}, extzv@var{m}) + (extzvmisalign@var{m}, insv@var{m}, insvmisalign@var{m}): Document. + (insv, extv, extzv): Deprecate. + * optabs.def (insv_optab, extv_optab, extzv_optab) + (insvmisalign_optab, extvmisalign_optab, extzvmisalign_optab): + New optabs. + * optabs.c (get_optab_extraction_insn): New function. + (get_extraction_insn): Use it. + * config/mips/mips.md (extv): Split into... + (extvmisalign, extv): ...these new patterns. Rename + existing extv pattern to... + (*extv): ...this. + (extzv): Split into... + (extzvmisalign, extzv): ...these new patterns. Rename + existing extzv pattern to... + (*extzv): ...this. + (insv): Split into... + (insvmisalign, insv): ...these new patterns. Rename + existing insv pattern to... + (*insv): ...this. Use const_int_operand rather than + immediate_operand. + * config/mips/mips.c (mips_block_move_straight): Use set_mem_size + to set the size of BLKmode accesses. + (mips_get_unaligned_mem): Require OP0 to be a BLKmode memory, + turning it from an "rtx *" to an rtx. + (mips_expand_ext_as_unaligned_load): Simplify for new optab + interface. Update call to mips_get_unaligned_mem. + (mips_expand_ins_as_unaligned_store): Update call to + mips_get_unaligned_mem. + 2012-11-18 Richard Sandiford * Makefile.in (recog.o): Add insn-codes.h. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 78c5a884ac7..b6a22907b23 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -7096,6 +7096,7 @@ mips_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length) else { rtx part = adjust_address (src, BLKmode, offset); + set_mem_size (part, delta); if (!mips_expand_ext_as_unaligned_load (regs[i], part, bits, 0, 0)) gcc_unreachable (); } @@ -7108,6 +7109,7 @@ mips_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length) else { rtx part = adjust_address (dest, BLKmode, offset); + set_mem_size (part, delta); if (!mips_expand_ins_as_unaligned_store (part, regs[i], bits, 0)) gcc_unreachable (); } @@ -7359,10 +7361,8 @@ mips_expand_atomic_qihi (union mips_gen_fn_ptrs generator, } /* Return true if it is possible to use left/right accesses for a - bitfield of WIDTH bits starting BITPOS bits into *OP. When - returning true, update *OP, *LEFT and *RIGHT as follows: - - *OP is a BLKmode reference to the whole field. + bitfield of WIDTH bits starting BITPOS bits into BLKmode memory OP. + When returning true, update *LEFT and *RIGHT as follows: *LEFT is a QImode reference to the first byte if big endian or the last byte if little endian. This address can be used in the @@ -7372,16 +7372,11 @@ mips_expand_atomic_qihi (union mips_gen_fn_ptrs generator, can be used in the patterning right-side instruction. */ static bool -mips_get_unaligned_mem (rtx *op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos, +mips_get_unaligned_mem (rtx op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos, rtx *left, rtx *right) { rtx first, last; - /* Check that the operand really is a MEM. Not all the extv and - extzv predicates are checked. */ - if (!MEM_P (*op)) - return false; - /* Check that the size is valid. */ if (width != 32 && (!TARGET_64BIT || width != 64)) return false; @@ -7394,20 +7389,12 @@ mips_get_unaligned_mem (rtx *op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos, /* Reject aligned bitfields: we want to use a normal load or store instead of a left/right pair. */ - if (MEM_ALIGN (*op) >= width) + if (MEM_ALIGN (op) >= width) return false; - /* Create a copy of *OP that refers to the whole field. This also has - the effect of legitimizing *OP's address for BLKmode, possibly - simplifying it. */ - *op = copy_rtx (adjust_address (*op, BLKmode, 0)); - set_mem_size (*op, width / BITS_PER_UNIT); - - /* Get references to both ends of the field. We deliberately don't - use the original QImode *OP for FIRST since the new BLKmode one - might have a simpler address. */ - first = adjust_address (*op, QImode, 0); - last = adjust_address (*op, QImode, width / BITS_PER_UNIT - 1); + /* Get references to both ends of the field. */ + first = adjust_address (op, QImode, 0); + last = adjust_address (op, QImode, width / BITS_PER_UNIT - 1); /* Allocate to LEFT and RIGHT according to endianness. LEFT should correspond to the MSB and RIGHT to the LSB. */ @@ -7434,14 +7421,6 @@ mips_expand_ext_as_unaligned_load (rtx dest, rtx src, HOST_WIDE_INT width, rtx left, right, temp; rtx dest1 = NULL_RTX; - /* If TARGET_64BIT, the destination of a 32-bit "extz" or "extzv" will - be a paradoxical word_mode subreg. This is the only case in which - we allow the destination to be larger than the source. */ - if (GET_CODE (dest) == SUBREG - && GET_MODE (dest) == DImode - && GET_MODE (SUBREG_REG (dest)) == SImode) - dest = SUBREG_REG (dest); - /* If TARGET_64BIT, the destination of a 32-bit "extz" or "extzv" will be a DImode, create a new temp and emit a zero extend at the end. */ if (GET_MODE (dest) == DImode @@ -7452,12 +7431,7 @@ mips_expand_ext_as_unaligned_load (rtx dest, rtx src, HOST_WIDE_INT width, dest = gen_reg_rtx (SImode); } - /* After the above adjustment, the destination must be the same - width as the source. */ - if (GET_MODE_BITSIZE (GET_MODE (dest)) != width) - return false; - - if (!mips_get_unaligned_mem (&src, width, bitpos, &left, &right)) + if (!mips_get_unaligned_mem (src, width, bitpos, &left, &right)) return false; temp = gen_reg_rtx (GET_MODE (dest)); @@ -7499,7 +7473,7 @@ mips_expand_ins_as_unaligned_store (rtx dest, rtx src, HOST_WIDE_INT width, rtx left, right; enum machine_mode mode; - if (!mips_get_unaligned_mem (&dest, width, bitpos, &left, &right)) + if (!mips_get_unaligned_mem (dest, width, bitpos, &left, &right)) return false; mode = mode_for_size (width, MODE_INT, 0); diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index f6a13129d60..a3aa922198c 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -3777,11 +3777,11 @@ ;; Bit field extract patterns which use lwl/lwr or ldl/ldr. -(define_expand "extv" - [(set (match_operand 0 "register_operand") - (sign_extract (match_operand 1 "nonimmediate_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] +(define_expand "extvmisalign" + [(set (match_operand:GPR 0 "register_operand") + (sign_extract:GPR (match_operand:BLK 1 "memory_operand") + (match_operand 2 "const_int_operand") + (match_operand 3 "const_int_operand")))] "!TARGET_MIPS16" { if (mips_expand_ext_as_unaligned_load (operands[0], operands[1], @@ -3789,22 +3789,22 @@ INTVAL (operands[3]), /*unsigned=*/ false)) DONE; - else if (register_operand (operands[1], GET_MODE (operands[0])) - && ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32) - { - if (GET_MODE (operands[0]) == DImode) - emit_insn (gen_extvdi (operands[0], operands[1], operands[2], - operands[3])); - else - emit_insn (gen_extvsi (operands[0], operands[1], operands[2], - operands[3])); - DONE; - } else FAIL; }) -(define_insn "extv" +(define_expand "extv" + [(set (match_operand:GPR 0 "register_operand") + (sign_extract:GPR (match_operand:GPR 1 "register_operand") + (match_operand 2 "const_int_operand") + (match_operand 3 "const_int_operand")))] + "ISA_HAS_EXTS" +{ + if (UINTVAL (operands[2]) > 32) + FAIL; +}) + +(define_insn "*extv" [(set (match_operand:GPR 0 "register_operand" "=d") (sign_extract:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand 2 "const_int_operand" "") @@ -3814,35 +3814,35 @@ [(set_attr "type" "arith") (set_attr "mode" "")]) - -(define_expand "extzv" - [(set (match_operand 0 "register_operand") - (zero_extract (match_operand 1 "nonimmediate_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] +(define_expand "extzvmisalign" + [(set (match_operand:GPR 0 "register_operand") + (zero_extract:GPR (match_operand:BLK 1 "memory_operand") + (match_operand 2 "const_int_operand") + (match_operand 3 "const_int_operand")))] "!TARGET_MIPS16" { if (mips_expand_ext_as_unaligned_load (operands[0], operands[1], INTVAL (operands[2]), INTVAL (operands[3]), - /*unsigned=*/true)) + /*unsigned=*/ true)) DONE; - else if (mips_use_ins_ext_p (operands[1], INTVAL (operands[2]), - INTVAL (operands[3]))) - { - if (GET_MODE (operands[0]) == DImode) - emit_insn (gen_extzvdi (operands[0], operands[1], operands[2], - operands[3])); - else - emit_insn (gen_extzvsi (operands[0], operands[1], operands[2], - operands[3])); - DONE; - } else FAIL; }) -(define_insn "extzv" +(define_expand "extzv" + [(set (match_operand:GPR 0 "register_operand") + (zero_extract:GPR (match_operand:GPR 1 "register_operand") + (match_operand 2 "const_int_operand") + (match_operand 3 "const_int_operand")))] + "" +{ + if (!mips_use_ins_ext_p (operands[1], INTVAL (operands[2]), + INTVAL (operands[3]))) + FAIL; +}) + +(define_insn "*extzv" [(set (match_operand:GPR 0 "register_operand" "=d") (zero_extract:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand 2 "const_int_operand" "") @@ -3865,36 +3865,37 @@ (set_attr "mode" "SI")]) -(define_expand "insv" - [(set (zero_extract (match_operand 0 "nonimmediate_operand") - (match_operand 1 "immediate_operand") - (match_operand 2 "immediate_operand")) - (match_operand 3 "reg_or_0_operand"))] +(define_expand "insvmisalign" + [(set (zero_extract:GPR (match_operand:BLK 0 "memory_operand") + (match_operand 1 "const_int_operand") + (match_operand 2 "const_int_operand")) + (match_operand:GPR 3 "reg_or_0_operand"))] "!TARGET_MIPS16" { if (mips_expand_ins_as_unaligned_store (operands[0], operands[3], INTVAL (operands[1]), INTVAL (operands[2]))) DONE; - else if (mips_use_ins_ext_p (operands[0], INTVAL (operands[1]), - INTVAL (operands[2]))) - { - if (GET_MODE (operands[0]) == DImode) - emit_insn (gen_insvdi (operands[0], operands[1], operands[2], - operands[3])); - else - emit_insn (gen_insvsi (operands[0], operands[1], operands[2], - operands[3])); - DONE; - } - else - FAIL; + else + FAIL; }) -(define_insn "insv" +(define_expand "insv" + [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand") + (match_operand 1 "const_int_operand") + (match_operand 2 "const_int_operand")) + (match_operand:GPR 3 "reg_or_0_operand"))] + "" +{ + if (!mips_use_ins_ext_p (operands[0], INTVAL (operands[1]), + INTVAL (operands[2]))) + FAIL; +}) + +(define_insn "*insv" [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+d") - (match_operand:SI 1 "immediate_operand" "I") - (match_operand:SI 2 "immediate_operand" "I")) + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) (match_operand:GPR 3 "reg_or_0_operand" "dJ"))] "mips_use_ins_ext_p (operands[0], INTVAL (operands[1]), INTVAL (operands[2]))" diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 396bf43fd37..6c648eed178 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5294,6 +5294,62 @@ Convert unsigned integer operand 1 of mode @var{m} to fixed-point mode When overflows or underflows happen, the instruction saturates the results to the maximum or the minimum. +@cindex @code{extv@var{m}} instruction pattern +@item @samp{extv@var{m}} +Extract a bit-field from register operand 1, sign-extend it, and store +it in operand 0. Operand 2 specifies the width of the field in bits +and operand 3 the starting bit, which counts from the most significant +bit if @samp{BITS_BIG_ENDIAN} is true and from the least significant bit +otherwise. + +Operands 0 and 1 both have mode @var{m}. Operands 2 and 3 have a +target-specific mode. + +@cindex @code{extvmisalign@var{m}} instruction pattern +@item @samp{extvmisalign@var{m}} +Extract a bit-field from memory operand 1, sign extend it, and store +it in operand 0. Operand 2 specifies the width in bits and operand 3 +the starting bit. The starting bit is always somewhere in the first byte of +operand 1; it counts from the most significant bit if @samp{BITS_BIG_ENDIAN} +is true and from the least significant bit otherwise. + +Operand 0 has mode @var{m} while operand 1 has @code{BLK} mode. +Operands 2 and 3 have a target-specific mode. + +The instruction must not read beyond the last byte of the bit-field. + +@cindex @code{extzv@var{m}} instruction pattern +@item @samp{extzv@var{m}} +Like @samp{extv@var{m}} except that the bit-field value is zero-extended. + +@cindex @code{extzvmisalign@var{m}} instruction pattern +@item @samp{extzvmisalign@var{m}} +Like @samp{extvmisalign@var{m}} except that the bit-field value is +zero-extended. + +@cindex @code{insv@var{m}} instruction pattern +@item @samp{insv@var{m}} +Insert operand 3 into a bit-field of register operand 0. Operand 1 +specifies the width of the field in bits and operand 2 the starting bit, +which counts from the most significant bit if @samp{BITS_BIG_ENDIAN} +is true and from the least significant bit otherwise. + +Operands 0 and 3 both have mode @var{m}. Operands 1 and 2 have a +target-specific mode. + +@cindex @code{insvmisalign@var{m}} instruction pattern +@item @samp{insvmisalign@var{m}} +Insert operand 3 into a bit-field of memory operand 0. Operand 1 +specifies the width of the field in bits and operand 2 the starting bit. +The starting bit is always somewhere in the first byte of operand 0; +it counts from the most significant bit if @samp{BITS_BIG_ENDIAN} +is true and from the least significant bit otherwise. + +Operand 3 has mode @var{m} while operand 0 has @code{BLK} mode. +Operands 1 and 2 have a target-specific mode. + +The instruction must not read or write beyond the last byte of the bit-field. + @cindex @code{extv} instruction pattern @item @samp{extv} Extract a bit-field from operand 1 (a register or memory operand), where @@ -5309,10 +5365,16 @@ for operands 2 and 3 and the constant is never zero for operand 2. The bit-field value is sign-extended to a full word integer before it is stored in operand 0. +This pattern is deprecated; please use @samp{extv@var{m}} and +@code{extvmisalign@var{m}} instead. + @cindex @code{extzv} instruction pattern @item @samp{extzv} Like @samp{extv} except that the bit-field value is zero-extended. +This pattern is deprecated; please use @samp{extzv@var{m}} and +@code{extzvmisalign@var{m}} instead. + @cindex @code{insv} instruction pattern @item @samp{insv} Store operand 3 (which must be valid for @code{word_mode}) into a @@ -5324,6 +5386,9 @@ Operands 1 and 2 must be valid for @code{word_mode}. The RTL generation pass generates this instruction only with constants for operands 1 and 2 and the constant is never zero for operand 1. +This pattern is deprecated; please use @samp{insv@var{m}} and +@code{insvmisalign@var{m}} instead. + @cindex @code{mov@var{mode}cc} instruction pattern @item @samp{mov@var{mode}cc} Conditionally move operand 2 or operand 3 into operand 0 according to the diff --git a/gcc/optabs.c b/gcc/optabs.c index 66c0337b0fd..353727f3324 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -8294,6 +8294,35 @@ get_traditional_extraction_insn (extraction_insn *insn, return true; } +/* Return true if an optab exists to perform an insertion or extraction + of type TYPE in mode MODE. Describe the instruction in *INSN if so. + + REG_OPTAB is the optab to use for register structures and + MISALIGN_OPTAB is the optab to use for misaligned memory structures. + POS_OP is the operand number of the bit position. */ + +static bool +get_optab_extraction_insn (struct extraction_insn *insn, + enum extraction_type type, + enum machine_mode mode, direct_optab reg_optab, + direct_optab misalign_optab, int pos_op) +{ + direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab); + enum insn_code icode = direct_optab_handler (optab, mode); + if (icode == CODE_FOR_nothing) + return false; + + const struct insn_data_d *data = &insn_data[icode]; + + insn->icode = icode; + insn->field_mode = mode; + insn->struct_mode = (type == ET_unaligned_mem ? BLKmode : mode); + insn->pos_mode = data->operand[pos_op].mode; + if (insn->pos_mode == VOIDmode) + insn->pos_mode = word_mode; + return true; +} + /* Return true if an instruction exists to perform an insertion or extraction (PATTERN says which) of type TYPE in mode MODE. Describe the instruction in *INSN if so. */ @@ -8311,21 +8340,24 @@ get_extraction_insn (extraction_insn *insn, && get_traditional_extraction_insn (insn, type, mode, CODE_FOR_insv, 0, 3)) return true; - return false; + return get_optab_extraction_insn (insn, type, mode, insv_optab, + insvmisalign_optab, 2); case EP_extv: if (HAVE_extv && get_traditional_extraction_insn (insn, type, mode, CODE_FOR_extv, 1, 0)) return true; - return false; + return get_optab_extraction_insn (insn, type, mode, extv_optab, + extvmisalign_optab, 3); case EP_extzv: if (HAVE_extzv && get_traditional_extraction_insn (insn, type, mode, CODE_FOR_extzv, 1, 0)) return true; - return false; + return get_optab_extraction_insn (insn, type, mode, extzv_optab, + extzvmisalign_optab, 3); default: gcc_unreachable (); diff --git a/gcc/optabs.def b/gcc/optabs.def index b483b0274e7..559726b17d2 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -171,6 +171,12 @@ OPTAB_DC(mov_optab, "mov$a", SET) OPTAB_DC(movstrict_optab, "movstrict$a", STRICT_LOW_PART) OPTAB_D (movmisalign_optab, "movmisalign$a") OPTAB_D (storent_optab, "storent$a") +OPTAB_D (insv_optab, "insv$a") +OPTAB_D (extv_optab, "extv$a") +OPTAB_D (extzv_optab, "extzv$a") +OPTAB_D (insvmisalign_optab, "insvmisalign$a") +OPTAB_D (extvmisalign_optab, "extvmisalign$a") +OPTAB_D (extzvmisalign_optab, "extzvmisalign$a") OPTAB_D (push_optab, "push$a1") OPTAB_D (reload_in_optab, "reload_in$a") OPTAB_D (reload_out_optab, "reload_out$a")