diff options
author | rsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-11-18 17:33:38 +0000 |
---|---|---|
committer | rsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-11-18 17:33:38 +0000 |
commit | 2642796685af2c90aa6c18a3bba03f5c571f87bd (patch) | |
tree | 322c854e5205121b0545f58847a6f3aa5e4c0b36 /gcc | |
parent | 4ed6cf776004b2e0a22047c3c0296c8f0493fe36 (diff) | |
download | gcc-2642796685af2c90aa6c18a3bba03f5c571f87bd.tar.gz |
gcc/
* Makefile.in (recog.o): Add insn-codes.h.
* expr.h (extraction_pattern): Move to optabs.h.
(mode_for_extraction): Delete.
* optabs.h (extraction_insn): New structure.
(extraction_pattern): Moved from expr.h.
(get_best_reg_extraction_insn, get_best_mem_extraction_insn): Declare.
* optabs.c (HAVE_insv, CODE_FOR_insv, HAVE_extv, CODE_FOR_extv)
(HAVE_extzv, CODE_FOR_extzv): Provide defaults.
(extraction_type): New enum.
(get_traditional_extraction_insn, get_extraction_insn)
(get_best_reg_extraction_insn, get_best_mem_extraction_insn):
New functions.
* combine.c (make_extraction): Use get_best_reg_extraction_insn
instead of mode_for_extraction.
* expmed.c (HAVE_insv, CODE_FOR_insv, gen_insv, HAVE_extv)
(CODE_FOR_extv, gen_extv, HAVE_extzv, CODE_FOR_extzv, gen_extzv):
Remove fallback definitions.
(mode_for_extraction): Delete.
(adjust_bit_field_mem_for_reg): New function.
(store_bit_field_using_insv): Replace OP_MODE parameter with
an extraction_insn. Pass struct_mode to narrow_bit_field_mem.
(extract_bit_field_using_extv): Likewise EXT_MODE.
(store_bit_field_1): Use get_best_reg_extraction_insn and
get_best_mem_extraction_insn instead of mode_for_extraction.
Use adjust_bit_field_mem_for_reg when forcing memory to a
register and doing a register insertion. Update calls to
store_bit_field_using_insv.
(extract_bit_field_1): Likewise extractions and calls to
extract_bit_field_using_extv.
(store_Bit_field): When narrowing to a bitregion, don't use the
insv mode as a limit.
* recog.c: (HAVE_extv, CODE_FOR_extv, HAVE_extzv, CODE_FOR_extzv):
Provide defaults.
(simplify_while_replacing): Use insn_data instead of
mode_for_extraction.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@193605 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 38 | ||||
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/combine.c | 38 | ||||
-rw-r--r-- | gcc/expmed.c | 306 | ||||
-rw-r--r-- | gcc/expr.h | 8 | ||||
-rw-r--r-- | gcc/optabs.c | 173 | ||||
-rw-r--r-- | gcc/optabs.h | 32 | ||||
-rw-r--r-- | gcc/recog.c | 29 |
8 files changed, 396 insertions, 230 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c153f732015..9361e357aea 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,43 @@ 2012-11-18 Richard Sandiford <rdsandiford@googlemail.com> + * Makefile.in (recog.o): Add insn-codes.h. + * expr.h (extraction_pattern): Move to optabs.h. + (mode_for_extraction): Delete. + * optabs.h (extraction_insn): New structure. + (extraction_pattern): Moved from expr.h. + (get_best_reg_extraction_insn, get_best_mem_extraction_insn): Declare. + * optabs.c (HAVE_insv, CODE_FOR_insv, HAVE_extv, CODE_FOR_extv) + (HAVE_extzv, CODE_FOR_extzv): Provide defaults. + (extraction_type): New enum. + (get_traditional_extraction_insn, get_extraction_insn) + (get_best_reg_extraction_insn, get_best_mem_extraction_insn): + New functions. + * combine.c (make_extraction): Use get_best_reg_extraction_insn + instead of mode_for_extraction. + * expmed.c (HAVE_insv, CODE_FOR_insv, gen_insv, HAVE_extv) + (CODE_FOR_extv, gen_extv, HAVE_extzv, CODE_FOR_extzv, gen_extzv): + Remove fallback definitions. + (mode_for_extraction): Delete. + (adjust_bit_field_mem_for_reg): New function. + (store_bit_field_using_insv): Replace OP_MODE parameter with + an extraction_insn. Pass struct_mode to narrow_bit_field_mem. + (extract_bit_field_using_extv): Likewise EXT_MODE. + (store_bit_field_1): Use get_best_reg_extraction_insn and + get_best_mem_extraction_insn instead of mode_for_extraction. + Use adjust_bit_field_mem_for_reg when forcing memory to a + register and doing a register insertion. Update calls to + store_bit_field_using_insv. + (extract_bit_field_1): Likewise extractions and calls to + extract_bit_field_using_extv. + (store_Bit_field): When narrowing to a bitregion, don't use the + insv mode as a limit. + * recog.c: (HAVE_extv, CODE_FOR_extv, HAVE_extzv, CODE_FOR_extzv): + Provide defaults. + (simplify_while_replacing): Use insn_data instead of + mode_for_extraction. + +2012-11-18 Richard Sandiford <rdsandiford@googlemail.com> + * stor-layout.c (bit_field_mode_iterator::bit_field_mode_iterator): Set up a default value of bitregion_end_. (bit_field_mode_iterator::next_mode): Always apply bitregion_end_ diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 0a46425a409..d74e7b3c0dc 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -3355,7 +3355,7 @@ recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \ $(FUNCTION_H) $(BASIC_BLOCK_H) $(REGS_H) $(RECOG_H) $(EXPR_H) \ $(FLAGS_H) insn-config.h $(INSN_ATTR_H) reload.h \ addresses.h $(TM_P_H) $(TREE_PASS_H) hard-reg-set.h \ - $(DF_H) $(DBGCNT_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) + $(DF_H) $(DBGCNT_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) insn-codes.h reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_ERROR_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \ insn-config.h reload.h $(FUNCTION_H) $(TM_P_H) $(GGC_H) \ diff --git a/gcc/combine.c b/gcc/combine.c index a3583e2013a..abd67e8ab9c 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -7179,29 +7179,24 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos, || (pos_rtx != 0 && len != 1))) return 0; - /* Get the mode to use should INNER not be a MEM, the mode for the position, - and the mode for the result. */ - if (in_dest && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE) - { - wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0); - pos_mode = mode_for_extraction (EP_insv, 2); - extraction_mode = mode_for_extraction (EP_insv, 3); - } + enum extraction_pattern pattern = (in_dest ? EP_insv + : unsignedp ? EP_extzv : EP_extv); - if (! in_dest && unsignedp - && mode_for_extraction (EP_extzv, -1) != MAX_MACHINE_MODE) - { - wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1); - pos_mode = mode_for_extraction (EP_extzv, 3); - extraction_mode = mode_for_extraction (EP_extzv, 0); - } + /* If INNER is not from memory, we want it to have the mode of a register + extraction pattern's structure operand, or word_mode if there is no + such pattern. The same applies to extraction_mode and pos_mode + and their respective operands. - if (! in_dest && ! unsignedp - && mode_for_extraction (EP_extv, -1) != MAX_MACHINE_MODE) + For memory, assume that the desired extraction_mode and pos_mode + are the same as for a register operation, since at present we don't + have named patterns for aligned memory structures. */ + struct extraction_insn insn; + if (get_best_reg_extraction_insn (&insn, pattern, + GET_MODE_BITSIZE (inner_mode), mode)) { - wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1); - pos_mode = mode_for_extraction (EP_extv, 3); - extraction_mode = mode_for_extraction (EP_extv, 0); + wanted_inner_reg_mode = insn.struct_mode; + pos_mode = insn.pos_mode; + extraction_mode = insn.field_mode; } /* Never narrow an object, since that might not be safe. */ @@ -7210,9 +7205,6 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos, && GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode)) extraction_mode = mode; - /* If this is not from memory, the desired mode is the preferred mode - for an extraction pattern's first input operand, or word_mode if there - is none. */ if (!MEM_P (inner)) wanted_inner_mode = wanted_inner_reg_mode; else diff --git a/gcc/expmed.c b/gcc/expmed.c index 106b78b7021..752aecdaf17 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -69,23 +69,6 @@ static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT); /* Test whether a value is zero of a power of two. */ #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0) -/* Reduce conditional compilation elsewhere. */ -#ifndef HAVE_insv -#define HAVE_insv 0 -#define CODE_FOR_insv CODE_FOR_nothing -#define gen_insv(a,b,c,d) NULL_RTX -#endif -#ifndef HAVE_extv -#define HAVE_extv 0 -#define CODE_FOR_extv CODE_FOR_nothing -#define gen_extv(a,b,c,d) NULL_RTX -#endif -#ifndef HAVE_extzv -#define HAVE_extzv 0 -#define CODE_FOR_extzv CODE_FOR_nothing -#define gen_extzv(a,b,c,d) NULL_RTX -#endif - struct init_expmed_rtl { struct rtx_def reg; rtunion reg_fld[2]; @@ -338,55 +321,6 @@ negate_rtx (enum machine_mode mode, rtx x) return result; } -/* Report on the availability of insv/extv/extzv and the desired mode - of each of their operands. Returns MAX_MACHINE_MODE if HAVE_foo - is false; else the mode of the specified operand. If OPNO is -1, - all the caller cares about is whether the insn is available. */ -enum machine_mode -mode_for_extraction (enum extraction_pattern pattern, int opno) -{ - const struct insn_data_d *data; - - switch (pattern) - { - case EP_insv: - if (HAVE_insv) - { - data = &insn_data[CODE_FOR_insv]; - break; - } - return MAX_MACHINE_MODE; - - case EP_extv: - if (HAVE_extv) - { - data = &insn_data[CODE_FOR_extv]; - break; - } - return MAX_MACHINE_MODE; - - case EP_extzv: - if (HAVE_extzv) - { - data = &insn_data[CODE_FOR_extzv]; - break; - } - return MAX_MACHINE_MODE; - - default: - gcc_unreachable (); - } - - if (opno == -1) - return VOIDmode; - - /* Everyone who uses this function used to follow it with - if (result == VOIDmode) result = word_mode; */ - if (data->operand[opno].mode == VOIDmode) - return word_mode; - return data->operand[opno].mode; -} - /* Adjust bitfield memory MEM so that it points to the first unit of mode MODE that contains a bitfield of size BITSIZE at bit position BITNUM. If MODE is BLKmode, return a reference to every byte in the bitfield. @@ -415,6 +349,57 @@ narrow_bit_field_mem (rtx mem, enum machine_mode mode, } } +/* The caller wants to perform insertion or extraction PATTERN on a + bitfield of size BITSIZE at BITNUM bits into memory operand OP0. + BITREGION_START and BITREGION_END are as for store_bit_field + and FIELDMODE is the natural mode of the field. + + Search for a mode that is compatible with the memory access + restrictions and (where applicable) with a register insertion or + extraction. Return the new memory on success, storing the adjusted + bit position in *NEW_BITNUM. Return null otherwise. */ + +static rtx +adjust_bit_field_mem_for_reg (enum extraction_pattern pattern, + rtx op0, HOST_WIDE_INT bitsize, + HOST_WIDE_INT bitnum, + unsigned HOST_WIDE_INT bitregion_start, + unsigned HOST_WIDE_INT bitregion_end, + enum machine_mode fieldmode, + unsigned HOST_WIDE_INT *new_bitnum) +{ + bit_field_mode_iterator iter (bitsize, bitnum, bitregion_start, + bitregion_end, MEM_ALIGN (op0), + MEM_VOLATILE_P (op0)); + enum machine_mode best_mode; + if (iter.next_mode (&best_mode)) + { + /* We can use a memory in BEST_MODE. See whether this is true for + any wider modes. All other things being equal, we prefer to + use the widest mode possible because it tends to expose more + CSE opportunities. */ + if (!iter.prefer_smaller_modes ()) + { + /* Limit the search to the mode required by the corresponding + register insertion or extraction instruction, if any. */ + enum machine_mode limit_mode = word_mode; + extraction_insn insn; + if (get_best_reg_extraction_insn (&insn, pattern, + GET_MODE_BITSIZE (best_mode), + fieldmode)) + limit_mode = insn.field_mode; + + enum machine_mode wider_mode; + while (iter.next_mode (&wider_mode) + && GET_MODE_SIZE (wider_mode) <= GET_MODE_SIZE (limit_mode)) + best_mode = wider_mode; + } + return narrow_bit_field_mem (op0, best_mode, bitsize, bitnum, + new_bitnum); + } + return NULL_RTX; +} + /* Return true if a bitfield of size BITSIZE at bit number BITNUM within a structure of mode STRUCT_MODE represents a lowpart subreg. The subreg offset is then BITNUM / BITS_PER_UNIT. */ @@ -432,14 +417,13 @@ lowpart_bit_field_p (unsigned HOST_WIDE_INT bitnum, return bitnum % BITS_PER_WORD == 0; } -/* Try to use an insv pattern to store VALUE into a field of OP0. - OP_MODE is the mode of the insertion and BITSIZE and BITNUM are - as for store_bit_field. */ +/* Try to use instruction INSV to store VALUE into a field of OP0. + BITSIZE and BITNUM are as for store_bit_field. */ static bool -store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize, - unsigned HOST_WIDE_INT bitnum, rtx value, - enum machine_mode op_mode) +store_bit_field_using_insv (const extraction_insn *insv, rtx op0, + unsigned HOST_WIDE_INT bitsize, + unsigned HOST_WIDE_INT bitnum, rtx value) { struct expand_operand ops[4]; rtx value1; @@ -447,13 +431,15 @@ store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize, rtx last = get_last_insn (); bool copy_back = false; + enum machine_mode op_mode = insv->field_mode; unsigned int unit = GET_MODE_BITSIZE (op_mode); if (bitsize == 0 || bitsize > unit) return false; if (MEM_P (xop0)) /* Get a reference to the first byte of the field. */ - xop0 = narrow_bit_field_mem (xop0, byte_mode, bitsize, bitnum, &bitnum); + xop0 = narrow_bit_field_mem (xop0, insv->struct_mode, bitsize, bitnum, + &bitnum); else { /* Convert from counting within OP0 to counting in OP_MODE. */ @@ -533,7 +519,7 @@ store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize, create_integer_operand (&ops[1], bitsize); create_integer_operand (&ops[2], bitnum); create_input_operand (&ops[3], value1, op_mode); - if (maybe_expand_insn (CODE_FOR_insv, 4, ops)) + if (maybe_expand_insn (insv->icode, 4, ops)) { if (copy_back) convert_move (op0, xop0, true); @@ -807,68 +793,38 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, within a word. If the destination is a register, it too fits in a word. */ - enum machine_mode op_mode = mode_for_extraction (EP_insv, 3); - if (op_mode != MAX_MACHINE_MODE - && !MEM_P (op0) - && store_bit_field_using_insv (op0, bitsize, bitnum, value, op_mode)) + extraction_insn insv; + if (!MEM_P (op0) + && get_best_reg_extraction_insn (&insv, EP_insv, + GET_MODE_BITSIZE (GET_MODE (op0)), + fieldmode) + && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value)) return true; /* If OP0 is a memory, try copying it to a register and seeing if a cheap register alternative is available. */ - if (op_mode != MAX_MACHINE_MODE && MEM_P (op0)) + if (MEM_P (op0)) { - enum machine_mode bestmode; - unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE; - - /* Do not use insv for volatile bitfields when - -fstrict-volatile-bitfields is in effect. */ - if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0) - /* Do not use insv if the bit region is restricted and - an op_mode integer doesn't fit into the restricted region. */ - && !(bitregion_end - && (bitnum - (bitnum % BITS_PER_UNIT) - + GET_MODE_BITSIZE (op_mode) - > bitregion_end + 1)) - && store_bit_field_using_insv (op0, bitsize, bitnum, value, op_mode)) + /* Do not use unaligned memory insvs for volatile bitfields when + -fstrict-volatile-bitfields is in effect. */ + if (!(MEM_VOLATILE_P (op0) + && flag_strict_volatile_bitfields > 0) + && get_best_mem_extraction_insn (&insv, EP_insv, bitsize, bitnum, + fieldmode) + && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value)) return true; - if (bitregion_end) - maxbits = bitregion_end - bitregion_start + 1; - - /* Get the mode to use for inserting into this field. If OP0 is - BLKmode, get the smallest mode consistent with the alignment. If - OP0 is a non-BLKmode object that is no wider than OP_MODE, use its - mode. Otherwise, use the smallest mode containing the field. */ - - if (GET_MODE (op0) == BLKmode - || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits - || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)) - bestmode = get_best_mode (bitsize, bitnum, - bitregion_start, bitregion_end, - MEM_ALIGN (op0), op_mode, - MEM_VOLATILE_P (op0)); - else - bestmode = GET_MODE (op0); + rtx last = get_last_insn (); - if (bestmode != VOIDmode - && GET_MODE_SIZE (bestmode) >= GET_MODE_SIZE (fieldmode) - && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0)) - && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0))) + /* Try loading part of OP0 into a register, inserting the bitfield + into that, and then copying the result back to OP0. */ + unsigned HOST_WIDE_INT bitpos; + rtx xop0 = adjust_bit_field_mem_for_reg (EP_insv, op0, bitsize, bitnum, + bitregion_start, bitregion_end, + fieldmode, &bitpos); + if (xop0) { - rtx last, tempreg, xop0; - unsigned HOST_WIDE_INT bitpos; - - last = get_last_insn (); - - /* Adjust address to point to the containing unit of - that mode. Compute the offset as a multiple of this unit, - counting in bytes. */ - xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum, - &bitpos); - - /* Fetch that unit, store the bitfield in it, then store - the unit. */ - tempreg = copy_to_reg (xop0); + rtx tempreg = copy_to_reg (xop0); if (store_bit_field_1 (tempreg, bitsize, bitpos, bitregion_start, bitregion_end, fieldmode, orig_value, false)) @@ -913,13 +869,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (MEM_P (str_rtx) && bitregion_start > 0) { enum machine_mode bestmode; - enum machine_mode op_mode; unsigned HOST_WIDE_INT offset; - op_mode = mode_for_extraction (EP_insv, 3); - if (op_mode == MAX_MACHINE_MODE) - op_mode = VOIDmode; - gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0); offset = bitregion_start / BITS_PER_UNIT; @@ -928,8 +879,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, bitregion_start = 0; bestmode = get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end, - MEM_ALIGN (str_rtx), - op_mode, + MEM_ALIGN (str_rtx), VOIDmode, MEM_VOLATILE_P (str_rtx)); str_rtx = adjust_address (str_rtx, bestmode, offset); } @@ -1251,15 +1201,16 @@ convert_extracted_bit_field (rtx x, enum machine_mode mode, are as for extract_bit_field. */ static rtx -extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize, +extract_bit_field_using_extv (const extraction_insn *extv, rtx op0, + unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target, - enum machine_mode mode, enum machine_mode tmode, - enum machine_mode ext_mode) + enum machine_mode mode, enum machine_mode tmode) { struct expand_operand ops[4]; rtx spec_target = target; rtx spec_target_subreg = 0; + enum machine_mode ext_mode = extv->field_mode; unsigned unit = GET_MODE_BITSIZE (ext_mode); if (bitsize == 0 || unit < bitsize) @@ -1267,7 +1218,8 @@ extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize, if (MEM_P (op0)) /* Get a reference to the first byte of the field. */ - op0 = narrow_bit_field_mem (op0, byte_mode, bitsize, bitnum, &bitnum); + op0 = narrow_bit_field_mem (op0, extv->struct_mode, bitsize, bitnum, + &bitnum); else { /* Convert from counting within OP0 to counting in EXT_MODE. */ @@ -1315,7 +1267,7 @@ extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize, create_fixed_operand (&ops[1], op0); create_integer_operand (&ops[2], bitsize); create_integer_operand (&ops[3], bitnum); - if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv, 4, ops)) + if (maybe_expand_insn (extv->icode, 4, ops)) { target = ops[0].value; if (target == spec_target) @@ -1341,7 +1293,6 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, { rtx op0 = str_rtx; enum machine_mode int_mode; - enum machine_mode ext_mode; enum machine_mode mode1; if (tmode == VOIDmode) @@ -1612,74 +1563,53 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, /* From here on we know the desired field is smaller than a word. If OP0 is a register, it too fits within a word. */ - - ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0); - if (ext_mode != MAX_MACHINE_MODE && !MEM_P (op0)) + enum extraction_pattern pattern = unsignedp ? EP_extzv : EP_extv; + extraction_insn extv; + if (!MEM_P (op0) + && get_best_reg_extraction_insn (&extv, pattern, bitnum + bitsize, + tmode)) { - rtx result = extract_bit_field_using_extv (op0, bitsize, bitnum, + rtx result = extract_bit_field_using_extv (&extv, op0, bitsize, bitnum, unsignedp, target, mode, - tmode, ext_mode); + tmode); if (result) return result; } /* If OP0 is a memory, try copying it to a register and seeing if a cheap register alternative is available. */ - if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0)) + if (MEM_P (op0)) { - enum machine_mode bestmode; - /* Do not use extv/extzv for volatile bitfields when -fstrict-volatile-bitfields is in effect. */ - if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0)) + if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0) + && get_best_mem_extraction_insn (&extv, pattern, bitsize, bitnum, + tmode)) { - rtx result = extract_bit_field_using_extv (op0, bitsize, bitnum, - unsignedp, target, mode, - tmode, ext_mode); + rtx result = extract_bit_field_using_extv (&extv, op0, bitsize, + bitnum, unsignedp, + target, mode, + tmode); if (result) return result; } - /* Get the mode to use for inserting into this field. If - OP0 is BLKmode, get the smallest mode consistent with the - alignment. If OP0 is a non-BLKmode object that is no - wider than EXT_MODE, use its mode. Otherwise, use the - smallest mode containing the field. */ - - if (GET_MODE (op0) == BLKmode - || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode)) - bestmode = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0), - ext_mode, MEM_VOLATILE_P (op0)); - else - bestmode = GET_MODE (op0); + rtx last = get_last_insn (); - if (bestmode != VOIDmode - && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0)) - && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0))) + /* Try loading part of OP0 into a register and extracting the + bitfield from that. */ + unsigned HOST_WIDE_INT bitpos; + rtx xop0 = adjust_bit_field_mem_for_reg (pattern, op0, bitsize, bitnum, + 0, 0, tmode, &bitpos); + if (xop0) { - unsigned HOST_WIDE_INT bitpos; - rtx xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum, - &bitpos); - - /* Make sure the register is big enough for the whole field. - (It might not be if bestmode == GET_MODE (op0) and the input - code was invalid.) */ - if (bitpos + bitsize <= GET_MODE_BITSIZE (bestmode)) - { - rtx last, result; - - last = get_last_insn (); - - /* Fetch it to a register in that size. */ - xop0 = force_reg (bestmode, xop0); - result = extract_bit_field_1 (xop0, bitsize, bitpos, + xop0 = copy_to_reg (xop0); + rtx result = extract_bit_field_1 (xop0, bitsize, bitpos, unsignedp, packedp, target, mode, tmode, false); - if (result) - return result; - - delete_insns_since (last); - } + if (result) + return result; + delete_insns_since (last); } } diff --git a/gcc/expr.h b/gcc/expr.h index f94f1db2224..c2168287cff 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -698,14 +698,6 @@ extern void probe_stack_range (HOST_WIDE_INT, rtx); in its original home. This becomes invalid if any more code is emitted. */ extern rtx hard_libcall_value (enum machine_mode, rtx); -/* Return the mode desired by operand N of a particular bitfield - insert/extract insn, or MAX_MACHINE_MODE if no such insn is - available. */ - -enum extraction_pattern { EP_insv, EP_extv, EP_extzv }; -extern enum machine_mode -mode_for_extraction (enum extraction_pattern, int); - extern void store_bit_field (rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, diff --git a/gcc/optabs.c b/gcc/optabs.c index bba93c2d561..66c0337b0fd 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -8239,4 +8239,177 @@ expand_jump_insn (enum insn_code icode, unsigned int nops, gcc_unreachable (); } +/* Reduce conditional compilation elsewhere. */ +#ifndef HAVE_insv +#define HAVE_insv 0 +#define CODE_FOR_insv CODE_FOR_nothing +#endif +#ifndef HAVE_extv +#define HAVE_extv 0 +#define CODE_FOR_extv CODE_FOR_nothing +#endif +#ifndef HAVE_extzv +#define HAVE_extzv 0 +#define CODE_FOR_extzv CODE_FOR_nothing +#endif + +/* Enumerates the possible types of structure operand to an + extraction_insn. */ +enum extraction_type { ET_unaligned_mem, ET_reg }; + +/* Check whether insv, extv or extzv pattern ICODE can be used for an + insertion or extraction of type TYPE on a structure of mode MODE. + Return true if so and fill in *INSN accordingly. STRUCT_OP is the + operand number of the structure (the first sign_extract or zero_extract + operand) and FIELD_OP is the operand number of the field (the other + side of the set from the sign_extract or zero_extract). */ + +static bool +get_traditional_extraction_insn (extraction_insn *insn, + enum extraction_type type, + enum machine_mode mode, + enum insn_code icode, + int struct_op, int field_op) +{ + const struct insn_data_d *data = &insn_data[icode]; + + enum machine_mode struct_mode = data->operand[struct_op].mode; + if (struct_mode == VOIDmode) + struct_mode = word_mode; + if (mode != struct_mode) + return false; + + enum machine_mode field_mode = data->operand[field_op].mode; + if (field_mode == VOIDmode) + field_mode = word_mode; + + enum machine_mode pos_mode = data->operand[struct_op + 2].mode; + if (pos_mode == VOIDmode) + pos_mode = word_mode; + + insn->icode = icode; + insn->field_mode = field_mode; + insn->struct_mode = (type == ET_unaligned_mem ? byte_mode : struct_mode); + insn->pos_mode = pos_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. */ + +static bool +get_extraction_insn (extraction_insn *insn, + enum extraction_pattern pattern, + enum extraction_type type, + enum machine_mode mode) +{ + switch (pattern) + { + case EP_insv: + if (HAVE_insv + && get_traditional_extraction_insn (insn, type, mode, + CODE_FOR_insv, 0, 3)) + return true; + return false; + + case EP_extv: + if (HAVE_extv + && get_traditional_extraction_insn (insn, type, mode, + CODE_FOR_extv, 1, 0)) + return true; + return false; + + case EP_extzv: + if (HAVE_extzv + && get_traditional_extraction_insn (insn, type, mode, + CODE_FOR_extzv, 1, 0)) + return true; + return false; + + default: + gcc_unreachable (); + } +} + +/* Return true if an instruction exists to access a field of mode + FIELDMODE in a structure that has STRUCT_BITS significant bits. + Describe the "best" such instruction in *INSN if so. PATTERN and + TYPE describe the type of insertion or extraction we want to perform. + + For an insertion, the number of significant structure bits includes + all bits of the target. For an extraction, it need only include the + most significant bit of the field. Larger widths are acceptable + in both cases. */ + +static bool +get_best_extraction_insn (extraction_insn *insn, + enum extraction_pattern pattern, + enum extraction_type type, + unsigned HOST_WIDE_INT struct_bits, + enum machine_mode field_mode) +{ + enum machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT); + while (mode != VOIDmode) + { + if (get_extraction_insn (insn, pattern, type, mode)) + { + while (mode != VOIDmode + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (field_mode) + && !TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode, + field_mode)) + { + get_extraction_insn (insn, pattern, type, mode); + mode = GET_MODE_WIDER_MODE (mode); + } + return true; + } + mode = GET_MODE_WIDER_MODE (mode); + } + return false; +} + +/* Return true if an instruction exists to access a field of mode + FIELDMODE in a register structure that has STRUCT_BITS significant bits. + Describe the "best" such instruction in *INSN if so. PATTERN describes + the type of insertion or extraction we want to perform. + + For an insertion, the number of significant structure bits includes + all bits of the target. For an extraction, it need only include the + most significant bit of the field. Larger widths are acceptable + in both cases. */ + +bool +get_best_reg_extraction_insn (extraction_insn *insn, + enum extraction_pattern pattern, + unsigned HOST_WIDE_INT struct_bits, + enum machine_mode field_mode) +{ + return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits, + field_mode); +} + +/* Return true if an instruction exists to access a field of BITSIZE + bits starting BITNUM bits into a memory structure. Describe the + "best" such instruction in *INSN if so. PATTERN describes the type + of insertion or extraction we want to perform and FIELDMODE is the + natural mode of the extracted field. + + The instructions considered here only access bytes that overlap + the bitfield; they do not touch any surrounding bytes. */ + +bool +get_best_mem_extraction_insn (extraction_insn *insn, + enum extraction_pattern pattern, + HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum, + enum machine_mode field_mode) +{ + unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT + + bitsize + + BITS_PER_UNIT - 1); + struct_bits -= struct_bits % BITS_PER_UNIT; + return get_best_extraction_insn (insn, pattern, ET_unaligned_mem, + struct_bits, field_mode); +} + #include "gt-optabs.h" diff --git a/gcc/optabs.h b/gcc/optabs.h index e0be2bac4fd..81aa1d049dc 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -323,6 +323,38 @@ extern rtx optab_libfunc (optab optab, enum machine_mode mode); extern rtx convert_optab_libfunc (convert_optab optab, enum machine_mode mode1, enum machine_mode mode2); +/* Describes an instruction that inserts or extracts a bitfield. */ +struct extraction_insn +{ + /* The code of the instruction. */ + enum insn_code icode; + + /* The mode that the structure operand should have. This is byte_mode + when using the legacy insv, extv and extzv patterns to access memory. */ + enum machine_mode struct_mode; + + /* The mode of the field to be inserted or extracted, and by extension + the mode of the insertion or extraction itself. */ + enum machine_mode field_mode; + + /* The mode of the field's bit position. This is only important + when the position is variable rather than constant. */ + enum machine_mode pos_mode; +}; + +/* Enumerates the possible extraction_insn operations. */ +enum extraction_pattern { EP_insv, EP_extv, EP_extzv }; + +extern bool get_best_reg_extraction_insn (extraction_insn *, + enum extraction_pattern, + unsigned HOST_WIDE_INT, + enum machine_mode); + +extern bool get_best_mem_extraction_insn (extraction_insn *, + enum extraction_pattern, + HOST_WIDE_INT, HOST_WIDE_INT, + enum machine_mode); + extern bool insn_operand_matches (enum insn_code icode, unsigned int opno, rtx operand); diff --git a/gcc/recog.c b/gcc/recog.c index 47e7f75e1dd..3c56703b1f5 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "tree-pass.h" #include "df.h" +#include "insn-codes.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -542,6 +543,16 @@ cancel_changes (int num) num_changes = num; } +/* Reduce conditional compilation elsewhere. */ +#ifndef HAVE_extv +#define HAVE_extv 0 +#define CODE_FOR_extv CODE_FOR_nothing +#endif +#ifndef HAVE_extzv +#define HAVE_extzv 0 +#define CODE_FOR_extzv CODE_FOR_nothing +#endif + /* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting rtx. */ @@ -628,19 +639,17 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object, enum machine_mode is_mode = GET_MODE (XEXP (x, 0)); int pos = INTVAL (XEXP (x, 2)); - if (GET_CODE (x) == ZERO_EXTRACT) + if (GET_CODE (x) == ZERO_EXTRACT && HAVE_extzv) { - enum machine_mode new_mode - = mode_for_extraction (EP_extzv, 1); - if (new_mode != MAX_MACHINE_MODE) - wanted_mode = new_mode; + wanted_mode = insn_data[CODE_FOR_extzv].operand[1].mode; + if (wanted_mode == VOIDmode) + wanted_mode = word_mode; } - else if (GET_CODE (x) == SIGN_EXTRACT) + else if (GET_CODE (x) == SIGN_EXTRACT && HAVE_extv) { - enum machine_mode new_mode - = mode_for_extraction (EP_extv, 1); - if (new_mode != MAX_MACHINE_MODE) - wanted_mode = new_mode; + wanted_mode = insn_data[CODE_FOR_extv].operand[1].mode; + if (wanted_mode == VOIDmode) + wanted_mode = word_mode; } /* If we have a narrower mode, we can do something. */ |