expr.h (store_bit_field): Don't return a value.

gcc/
	* expr.h (store_bit_field): Don't return a value.
	* expmed.c (check_predicate_volatile_ok): New function.
	(store_bit_field_1): New function, extracted from store_bit_field.
	Take a fallback_p argument and return true if the operation succeeded.
	Only use store_fixed_bit_field if fallback_p.  Don't recompute
	mode_for_extraction; use op_mode instead.  Try forcing memories
	into registers if the insv expander fails.
	(store_bit_field): Use store_bit_field_1 with fallback_p true.
	Don't return a value.
	(convert_extracted_bit_field): New function, extracted from
	store_bit_field.
	(extract_bit_field_1): Likewise.  Take a fallback_p argument
	and return NULL if the operation succeeded.  Only use
	extract_fixed_bit_field if fallback_p.  Only calculate one
	extraction mode.  Combine code for extv and extzv.  Try forcing
	memories into registers if the ext(z)v expander fails.
	(extract_bit_field): Use extract_bit_field_1 with fallback_p true.

gcc/testsuite/
	* gcc.target/mips/ins-1.c: New test.

From-SVN: r126972
This commit is contained in:
Richard Sandiford 2007-07-27 07:39:09 +00:00 committed by Richard Sandiford
parent ab34041dfe
commit 6d7db3c5df
5 changed files with 362 additions and 404 deletions

View File

@ -1,3 +1,23 @@
2007-07-27 Richard Sandiford <richard@codesourcery.com>
* expr.h (store_bit_field): Don't return a value.
* expmed.c (check_predicate_volatile_ok): New function.
(store_bit_field_1): New function, extracted from store_bit_field.
Take a fallback_p argument and return true if the operation succeeded.
Only use store_fixed_bit_field if fallback_p. Don't recompute
mode_for_extraction; use op_mode instead. Try forcing memories
into registers if the insv expander fails.
(store_bit_field): Use store_bit_field_1 with fallback_p true.
Don't return a value.
(convert_extracted_bit_field): New function, extracted from
store_bit_field.
(extract_bit_field_1): Likewise. Take a fallback_p argument
and return NULL if the operation succeeded. Only use
extract_fixed_bit_field if fallback_p. Only calculate one
extraction mode. Combine code for extv and extzv. Try forcing
memories into registers if the ext(z)v expander fails.
(extract_bit_field): Use extract_bit_field_1 with fallback_p true.
2007-07-27 Richard Sandiford <rsandifo@nildram.co.uk>
* df.h (df_mw_hardreg): Turn df_ref_type and df_ref_flags

View File

@ -327,26 +327,33 @@ mode_for_extraction (enum extraction_pattern pattern, int opno)
return data->operand[opno].mode;
}
/* Return true if X, of mode MODE, matches the predicate for operand
OPNO of instruction ICODE. Allow volatile memories, regardless of
the ambient volatile_ok setting. */
static bool
check_predicate_volatile_ok (enum insn_code icode, int opno,
rtx x, enum machine_mode mode)
{
bool save_volatile_ok, result;
save_volatile_ok = volatile_ok;
result = insn_data[(int) icode].operand[opno].predicate (x, mode);
volatile_ok = save_volatile_ok;
return result;
}
/* Generate code to store value from rtx VALUE
into a bit-field within structure STR_RTX
containing BITSIZE bits starting at bit BITNUM.
FIELDMODE is the machine-mode of the FIELD_DECL node for this field.
ALIGN is the alignment that STR_RTX is known to have.
TOTAL_SIZE is the size of the structure in bytes, or -1 if varying. */
/* A subroutine of store_bit_field, with the same arguments. Return true
if the operation could be implemented.
/* ??? Note that there are two different ideas here for how
to determine the size to count bits within, for a register.
One is BITS_PER_WORD, and the other is the size of operand 3
of the insv pattern.
If FALLBACK_P is true, fall back to store_fixed_bit_field if we have
no other way of implementing the operation. If FALLBACK_P is false,
return false instead. */
If operand 3 of the insv pattern is VOIDmode, then we will use BITS_PER_WORD
else, we use the mode of operand 3. */
rtx
store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
rtx value)
static bool
store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
rtx value, bool fallback_p)
{
unsigned int unit
= (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
@ -390,7 +397,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
lies completely outside that register. This can occur if the source
code contains an out-of-bounds access to a small array. */
if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
return value;
return true;
/* Use vec_set patterns for inserting parts of vectors whenever
available. */
@ -434,7 +441,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
{
emit_insn (seq);
emit_insn (pat);
return dest;
return true;
}
}
@ -466,7 +473,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
byte_offset);
emit_move_insn (op0, value);
return value;
return true;
}
/* Make sure we are playing with integral modes. Pun with subregs
@ -543,7 +550,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
+ (offset * UNITS_PER_WORD)),
value));
return value;
return true;
}
/* Handle fields bigger than a word. */
@ -559,6 +566,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i;
rtx last;
/* This is the mode we must force value to, so that there will be enough
subwords to extract. Note that fieldmode will often (always?) be
@ -569,6 +577,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if (fieldmode == VOIDmode)
fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
last = get_last_insn ();
for (i = 0; i < nwords; i++)
{
/* If I is 0, use the low-order word in both field and target;
@ -579,13 +588,18 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
* BITS_PER_WORD,
0)
: (int) i * BITS_PER_WORD);
rtx value_word = operand_subword_force (value, wordnum, fieldmode);
store_bit_field (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
bitnum + bit_offset, word_mode,
operand_subword_force (value, wordnum, fieldmode));
if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
bitnum + bit_offset, word_mode,
value_word, fallback_p))
{
delete_insns_since (last);
return false;
}
}
return value;
return true;
}
/* From here on we can assume that the field to be stored in is
@ -639,74 +653,27 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
&& insn_data[CODE_FOR_insv].operand[1].predicate (GEN_INT (bitsize),
VOIDmode))
VOIDmode)
&& check_predicate_volatile_ok (CODE_FOR_insv, 0, op0, VOIDmode))
{
int xbitpos = bitpos;
rtx value1;
rtx xop0 = op0;
rtx last = get_last_insn ();
rtx pat;
enum machine_mode maxmode = mode_for_extraction (EP_insv, 3);
int save_volatile_ok = volatile_ok;
volatile_ok = 1;
/* If this machine's insv can only insert into a register, copy OP0
into a register and save it back later. */
if (MEM_P (op0)
&& ! ((*insn_data[(int) CODE_FOR_insv].operand[0].predicate)
(op0, VOIDmode)))
{
rtx tempreg;
enum machine_mode bestmode;
/* 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 MAXMODE, 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 (maxmode))
bestmode
= get_best_mode (bitsize, bitnum, MEM_ALIGN (op0), maxmode,
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)))
goto insv_loses;
/* Adjust address to point to the containing unit of that mode.
Compute offset as multiple of this unit, counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
bitpos = bitnum % unit;
op0 = adjust_address (op0, bestmode, offset);
/* Fetch that unit, store the bitfield in it, then store
the unit. */
tempreg = copy_to_reg (op0);
store_bit_field (tempreg, bitsize, bitpos, fieldmode, orig_value);
emit_move_insn (op0, tempreg);
return value;
}
volatile_ok = save_volatile_ok;
/* Add OFFSET into OP0's address. */
if (MEM_P (xop0))
xop0 = adjust_address (xop0, byte_mode, offset);
/* If xop0 is a register, we need it in MAXMODE
/* If xop0 is a register, we need it in OP_MODE
to make it acceptable to the format of insv. */
if (GET_CODE (xop0) == SUBREG)
/* We can't just change the mode, because this might clobber op0,
and we will need the original value of op0 if insv fails. */
xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
@ -717,13 +684,13 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
/* We have been counting XBITPOS within UNIT.
Count instead within the size of the register. */
if (BITS_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (maxmode) - unit;
xbitpos += GET_MODE_BITSIZE (op_mode) - unit;
unit = GET_MODE_BITSIZE (maxmode);
unit = GET_MODE_BITSIZE (op_mode);
/* Convert VALUE to maxmode (which insv insn wants) in VALUE1. */
/* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */
value1 = value;
if (GET_MODE (value) != maxmode)
if (GET_MODE (value) != op_mode)
{
if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize)
{
@ -731,23 +698,23 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if it has all the bits we will actually use. However,
if we must narrow it, be sure we do it correctly. */
if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (maxmode))
if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (op_mode))
{
rtx tmp;
tmp = simplify_subreg (maxmode, value1, GET_MODE (value), 0);
tmp = simplify_subreg (op_mode, value1, GET_MODE (value), 0);
if (! tmp)
tmp = simplify_gen_subreg (maxmode,
tmp = simplify_gen_subreg (op_mode,
force_reg (GET_MODE (value),
value1),
GET_MODE (value), 0);
value1 = tmp;
}
else
value1 = gen_lowpart (maxmode, value1);
value1 = gen_lowpart (op_mode, value1);
}
else if (GET_CODE (value) == CONST_INT)
value1 = gen_int_mode (INTVAL (value), maxmode);
value1 = gen_int_mode (INTVAL (value), op_mode);
else
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
@ -759,23 +726,89 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
/* If this machine's insv insists on a register,
get VALUE1 into a register. */
if (! ((*insn_data[(int) CODE_FOR_insv].operand[3].predicate)
(value1, maxmode)))
value1 = force_reg (maxmode, value1);
(value1, op_mode)))
value1 = force_reg (op_mode, value1);
pat = gen_insv (xop0, GEN_INT (bitsize), GEN_INT (xbitpos), value1);
if (pat)
emit_insn (pat);
else
{
emit_insn (pat);
return true;
}
delete_insns_since (last);
}
/* If OP0 is a memory, try copying it to a register and seeing if a
cheap register alternative is available. */
if (HAVE_insv && MEM_P (op0))
{
enum machine_mode bestmode;
/* 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
|| (op_mode != MAX_MACHINE_MODE
&& GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
(op_mode == MAX_MACHINE_MODE
? VOIDmode : 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)))
{
rtx last, tempreg, xop0;
unsigned HOST_WIDE_INT xoffset, xbitpos;
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. */
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
xop0 = adjust_address (op0, bestmode, xoffset);
/* Fetch that unit, store the bitfield in it, then store
the unit. */
tempreg = copy_to_reg (xop0);
if (store_bit_field_1 (tempreg, bitsize, xbitpos,
fieldmode, orig_value, false))
{
emit_move_insn (xop0, tempreg);
return true;
}
delete_insns_since (last);
store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
}
}
else
insv_loses:
/* Insv is not available; store using shifts and boolean ops. */
store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
return value;
if (!fallback_p)
return false;
store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
return true;
}
/* Generate code to store value from rtx VALUE
into a bit-field within structure STR_RTX
containing BITSIZE bits starting at bit BITNUM.
FIELDMODE is the machine-mode of the FIELD_DECL node for this field. */
void
store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
rtx value)
{
if (!store_bit_field_1 (str_rtx, bitsize, bitnum, fieldmode, value, true))
gcc_unreachable ();
}
/* Use shifts and boolean operations to store VALUE
@ -1067,40 +1100,52 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
}
}
/* Generate code to extract a byte-field from STR_RTX
containing BITSIZE bits, starting at BITNUM,
and put it in TARGET if possible (if TARGET is nonzero).
Regardless of TARGET, we return the rtx for where the value is placed.
/* A subroutine of extract_bit_field_1 that converts return value X
to either MODE or TMODE. MODE, TMODE and UNSIGNEDP are arguments
to extract_bit_field. */
STR_RTX is the structure containing the byte (a REG or MEM).
UNSIGNEDP is nonzero if this is an unsigned bit field.
MODE is the natural mode of the field value once extracted.
TMODE is the mode the caller would like the value to have;
but the value may be returned with type MODE instead.
static rtx
convert_extracted_bit_field (rtx x, enum machine_mode mode,
enum machine_mode tmode, bool unsignedp)
{
if (GET_MODE (x) == tmode || GET_MODE (x) == mode)
return x;
TOTAL_SIZE is the size in bytes of the containing structure,
or -1 if varying.
/* If the x mode is not a scalar integral, first convert to the
integer mode of that size and then access it as a floating-point
value via a SUBREG. */
if (!SCALAR_INT_MODE_P (tmode))
{
enum machine_mode smode;
If a TARGET is specified and we can store in it at no extra cost,
we do so, and return TARGET.
Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred
if they are equally easy. */
smode = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
x = convert_to_mode (smode, x, unsignedp);
x = force_reg (smode, x);
return gen_lowpart (tmode, x);
}
rtx
extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
enum machine_mode mode, enum machine_mode tmode)
return convert_to_mode (tmode, x, unsignedp);
}
/* A subroutine of extract_bit_field, with the same arguments.
If FALLBACK_P is true, fall back to extract_fixed_bit_field
if we can find no other means of implementing the operation.
if FALLBACK_P is false, return NULL instead. */
static rtx
extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
enum machine_mode mode, enum machine_mode tmode,
bool fallback_p)
{
unsigned int unit
= (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
unsigned HOST_WIDE_INT offset, bitpos;
rtx op0 = str_rtx;
rtx spec_target = target;
rtx spec_target_subreg = 0;
enum machine_mode int_mode;
enum machine_mode extv_mode = mode_for_extraction (EP_extv, 0);
enum machine_mode extzv_mode = mode_for_extraction (EP_extzv, 0);
enum machine_mode ext_mode;
enum machine_mode mode1;
enum insn_code icode;
int byte_offset;
if (tmode == VOIDmode)
@ -1409,299 +1454,172 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
}
/* Now OFFSET is nonzero only for memory operands. */
if (unsignedp)
ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
icode = unsignedp ? CODE_FOR_extzv : CODE_FOR_extv;
if (ext_mode != MAX_MACHINE_MODE
&& bitsize > 0
&& GET_MODE_BITSIZE (ext_mode) >= bitsize
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
&& !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode)
&& !((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode)))
&& check_predicate_volatile_ok (icode, 1, op0, GET_MODE (op0)))
{
if (HAVE_extzv
&& bitsize > 0
&& GET_MODE_BITSIZE (extzv_mode) >= bitsize
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (extzv_mode))))
unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx last = get_last_insn ();
rtx xop0 = op0;
rtx xtarget = target;
rtx xspec_target = target;
rtx xspec_target_subreg = 0;
rtx pat;
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
xop0 = gen_rtx_SUBREG (ext_mode, xop0, 0);
if (MEM_P (xop0))
/* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
xbitpos = unit - bitsize - xbitpos;
/* Now convert from counting within UNIT to counting in EXT_MODE. */
if (BITS_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (ext_mode) - unit;
unit = GET_MODE_BITSIZE (ext_mode);
if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
if (GET_MODE (xtarget) != ext_mode)
{
unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx last = get_last_insn ();
rtx xop0 = op0;
rtx xtarget = target;
rtx xspec_target = spec_target;
rtx xspec_target_subreg = spec_target_subreg;
rtx pat;
enum machine_mode maxmode = mode_for_extraction (EP_extzv, 0);
if (MEM_P (xop0))
if (REG_P (xtarget))
{
int save_volatile_ok = volatile_ok;
volatile_ok = 1;
/* Is the memory operand acceptable? */
if (! ((*insn_data[(int) CODE_FOR_extzv].operand[1].predicate)
(xop0, GET_MODE (xop0))))
{
/* No, load into a reg and extract from there. */
enum machine_mode bestmode;
/* 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 MAXMODE, use its mode. Otherwise, use the
smallest mode containing the field. */
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
bestmode = get_best_mode (bitsize, bitnum,
MEM_ALIGN (xop0), maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
|| (SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (xop0))
&& GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (xop0)))
goto extzv_loses;
/* Compute offset as multiple of this unit,
counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
xop0 = adjust_address (xop0, bestmode, xoffset);
/* Make sure register is big enough for the whole field. */
if (xoffset * BITS_PER_UNIT + unit
< offset * BITS_PER_UNIT + bitsize)
goto extzv_loses;
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
/* XBITPOS counts within UNIT, which is what is expected. */
}
else
/* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset);
volatile_ok = save_volatile_ok;
}
/* If op0 is a register, we need it in MAXMODE (which is usually
SImode). to make it acceptable to the format of extzv. */
if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
goto extzv_loses;
if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
xbitpos = unit - bitsize - xbitpos;
/* Now convert from counting within UNIT to counting in MAXMODE. */
if (BITS_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (maxmode) - unit;
unit = GET_MODE_BITSIZE (maxmode);
if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
if (GET_MODE (xtarget) != maxmode)
{
if (REG_P (xtarget))
{
int wider = (GET_MODE_SIZE (maxmode)
> GET_MODE_SIZE (GET_MODE (xtarget)));
xtarget = gen_lowpart (maxmode, xtarget);
if (wider)
xspec_target_subreg = xtarget;
}
else
xtarget = gen_reg_rtx (maxmode);
}
/* If this machine's extzv insists on a register target,
make sure we have one. */
if (! ((*insn_data[(int) CODE_FOR_extzv].operand[0].predicate)
(xtarget, maxmode)))
xtarget = gen_reg_rtx (maxmode);
bitsize_rtx = GEN_INT (bitsize);
bitpos_rtx = GEN_INT (xbitpos);
pat = gen_extzv (xtarget, xop0, bitsize_rtx, bitpos_rtx);
if (pat)
{
emit_insn (pat);
target = xtarget;
spec_target = xspec_target;
spec_target_subreg = xspec_target_subreg;
xtarget = gen_lowpart (ext_mode, xtarget);
if (GET_MODE_SIZE (ext_mode)
> GET_MODE_SIZE (GET_MODE (xspec_target)))
xspec_target_subreg = xtarget;
}
else
{
delete_insns_since (last);
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 1);
}
xtarget = gen_reg_rtx (ext_mode);
}
else
extzv_loses:
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 1);
}
else
{
if (HAVE_extv
&& bitsize > 0
&& GET_MODE_BITSIZE (extv_mode) >= bitsize
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (extv_mode))))
/* If this machine's ext(z)v insists on a register target,
make sure we have one. */
if (!insn_data[(int) icode].operand[0].predicate (xtarget, ext_mode))
xtarget = gen_reg_rtx (ext_mode);
bitsize_rtx = GEN_INT (bitsize);
bitpos_rtx = GEN_INT (xbitpos);
pat = (unsignedp
? gen_extzv (xtarget, xop0, bitsize_rtx, bitpos_rtx)
: gen_extv (xtarget, xop0, bitsize_rtx, bitpos_rtx));
if (pat)
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx last = get_last_insn ();
rtx xop0 = op0, xtarget = target;
rtx xspec_target = spec_target;
rtx xspec_target_subreg = spec_target_subreg;
rtx pat;
enum machine_mode maxmode = mode_for_extraction (EP_extv, 0);
if (MEM_P (xop0))
{
/* Is the memory operand acceptable? */
if (! ((*insn_data[(int) CODE_FOR_extv].operand[1].predicate)
(xop0, GET_MODE (xop0))))
{
/* No, load into a reg and extract from there. */
enum machine_mode bestmode;
/* 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 MAXMODE, use its mode. Otherwise, use the
smallest mode containing the field. */
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
bestmode = get_best_mode (bitsize, bitnum,
MEM_ALIGN (xop0), maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
|| (SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (xop0))
&& GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (xop0)))
goto extv_loses;
/* Compute offset as multiple of this unit,
counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
xop0 = adjust_address (xop0, bestmode, xoffset);
/* Make sure register is big enough for the whole field. */
if (xoffset * BITS_PER_UNIT + unit
< offset * BITS_PER_UNIT + bitsize)
goto extv_loses;
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
/* XBITPOS counts within UNIT, which is what is expected. */
}
else
/* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset);
}
/* If op0 is a register, we need it in MAXMODE (which is usually
SImode) to make it acceptable to the format of extv. */
if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
goto extv_loses;
if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
xbitpos = unit - bitsize - xbitpos;
/* XBITPOS counts within a size of UNIT.
Adjust to count within a size of MAXMODE. */
if (BITS_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += (GET_MODE_BITSIZE (maxmode) - unit);
unit = GET_MODE_BITSIZE (maxmode);
if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
if (GET_MODE (xtarget) != maxmode)
{
if (REG_P (xtarget))
{
int wider = (GET_MODE_SIZE (maxmode)
> GET_MODE_SIZE (GET_MODE (xtarget)));
xtarget = gen_lowpart (maxmode, xtarget);
if (wider)
xspec_target_subreg = xtarget;
}
else
xtarget = gen_reg_rtx (maxmode);
}
/* If this machine's extv insists on a register target,
make sure we have one. */
if (! ((*insn_data[(int) CODE_FOR_extv].operand[0].predicate)
(xtarget, maxmode)))
xtarget = gen_reg_rtx (maxmode);
bitsize_rtx = GEN_INT (bitsize);
bitpos_rtx = GEN_INT (xbitpos);
pat = gen_extv (xtarget, xop0, bitsize_rtx, bitpos_rtx);
if (pat)
{
emit_insn (pat);
target = xtarget;
spec_target = xspec_target;
spec_target_subreg = xspec_target_subreg;
}
else
{
delete_insns_since (last);
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 0);
}
emit_insn (pat);
if (xtarget == xspec_target)
return xtarget;
if (xtarget == xspec_target_subreg)
return xspec_target;
return convert_extracted_bit_field (xtarget, mode, tmode, unsignedp);
}
else
extv_loses:
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 0);
delete_insns_since (last);
}
if (target == spec_target)
return target;
if (target == spec_target_subreg)
return spec_target;
if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
/* 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 the target mode is not a scalar integral, first convert to the
integer mode of that size and then access it as a floating-point
value via a SUBREG. */
if (!SCALAR_INT_MODE_P (tmode))
{
enum machine_mode smode
= mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
target = convert_to_mode (smode, target, unsignedp);
target = force_reg (smode, target);
return gen_lowpart (tmode, target);
}
enum machine_mode bestmode;
return convert_to_mode (tmode, target, unsignedp);
/* 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
|| (ext_mode != MAX_MACHINE_MODE
&& GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode)))
bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
(ext_mode == MAX_MACHINE_MODE
? VOIDmode : 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)))
{
unsigned HOST_WIDE_INT xoffset, xbitpos;
/* Compute the offset as a multiple of this unit,
counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
/* Make sure the register is big enough for the whole field. */
if (xoffset * BITS_PER_UNIT + unit
>= offset * BITS_PER_UNIT + bitsize)
{
rtx last, result, xop0;
last = get_last_insn ();
/* Fetch it to a register in that size. */
xop0 = adjust_address (op0, bestmode, xoffset);
xop0 = force_reg (bestmode, xop0);
result = extract_bit_field_1 (xop0, bitsize, xbitpos,
unsignedp, target,
mode, tmode, false);
if (result)
return result;
delete_insns_since (last);
}
}
}
return target;
if (!fallback_p)
return NULL;
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, unsignedp);
return convert_extracted_bit_field (target, mode, tmode, unsignedp);
}
/* Generate code to extract a byte-field from STR_RTX
containing BITSIZE bits, starting at BITNUM,
and put it in TARGET if possible (if TARGET is nonzero).
Regardless of TARGET, we return the rtx for where the value is placed.
STR_RTX is the structure containing the byte (a REG or MEM).
UNSIGNEDP is nonzero if this is an unsigned bit field.
MODE is the natural mode of the field value once extracted.
TMODE is the mode the caller would like the value to have;
but the value may be returned with type MODE instead.
If a TARGET is specified and we can store in it at no extra cost,
we do so, and return TARGET.
Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred
if they are equally easy. */
rtx
extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
enum machine_mode mode, enum machine_mode tmode)
{
return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp,
target, mode, tmode, true);
}
/* Extract a bit field using shifts and boolean operations

View File

@ -731,8 +731,8 @@ enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
extern enum machine_mode
mode_for_extraction (enum extraction_pattern, int);
extern rtx store_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, enum machine_mode, rtx);
extern void store_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, enum machine_mode, rtx);
extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int, rtx,
enum machine_mode, enum machine_mode);

View File

@ -1,3 +1,7 @@
2007-07-27 Richard Sandiford <richard@codesourcery.com>
* gcc.target/mips/ins-1.c: New test.
2007-07-26 Nathan Froyd <froydnj@codesourcery.com>
PR/19232

View File

@ -0,0 +1,16 @@
/* { dg-do compile } */
/* { dg-mips-options "-O -march=mips32r2 -mno-mips16" } */
/* { dg-final { scan-assembler "\tins\t" } } */
struct
{
unsigned int i : 2;
unsigned int j : 3;
unsigned int k : 4;
} s;
void
foo (void)
{
s.j = 1;
}