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:
parent
8b7d5dab44
commit
fcdd52b73c
8 changed files with 396 additions and 230 deletions
|
@ -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):
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
306
gcc/expmed.c
306
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
173
gcc/optabs.c
173
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"
|
||||
|
|
32
gcc/optabs.h
32
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);
|
||||
|
||||
|
|
29
gcc/recog.c
29
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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue