Makefile.in (recog.o): Add insn-codes.h.

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.

From-SVN: r193605
This commit is contained in:
Richard Sandiford 2012-11-18 17:33:38 +00:00 committed by Richard Sandiford
parent 8b7d5dab44
commit fcdd52b73c
8 changed files with 396 additions and 230 deletions

View File

@ -1,3 +1,41 @@
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):

View File

@ -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) \

View File

@ -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

View File

@ -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;
rtx last = get_last_insn ();
/* 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);
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. */
rtx last = get_last_insn ();
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);
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);
}
}

View File

@ -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,

View File

@ -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"

View File

@ -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);

View File

@ -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. */