machmode.h (bit_field_mode_iterator): New class.

gcc/
	* machmode.h (bit_field_mode_iterator): New class.
	(get_best_mode): Change final parameter to bool.
	* stor-layout.c (bit_field_mode_iterator::bit_field_mode_iterator)
	(bit_field_mode_iterator::next_mode): New functions, split out from...
	(get_best_mode): ...here.  Change final parameter to bool.
	Use bit_field_mode_iterator.

From-SVN: r193603
This commit is contained in:
Richard Sandiford 2012-11-18 17:33:01 +00:00 committed by Richard Sandiford
parent 26f8b97630
commit 073a544dd9
3 changed files with 134 additions and 61 deletions

View File

@ -1,3 +1,12 @@
2012-11-18 Richard Sandiford <rdsandiford@googlemail.com>
* machmode.h (bit_field_mode_iterator): New class.
(get_best_mode): Change final parameter to bool.
* stor-layout.c (bit_field_mode_iterator::bit_field_mode_iterator)
(bit_field_mode_iterator::next_mode): New functions, split out from...
(get_best_mode): ...here. Change final parameter to bool.
Use bit_field_mode_iterator.
2012-11-18 Richard Sandiford <rdsandiford@googlemail.com>
* expmed.c (narrow_bit_field_mem): New function.

View File

@ -259,13 +259,36 @@ extern enum machine_mode int_mode_for_mode (enum machine_mode);
extern enum machine_mode mode_for_vector (enum machine_mode, unsigned);
/* A class for iterating through possible bitfield modes. */
class bit_field_mode_iterator
{
public:
bit_field_mode_iterator (HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT,
unsigned int, bool);
bool next_mode (enum machine_mode *);
bool prefer_smaller_modes ();
private:
enum machine_mode mode_;
/* We use signed values here because the bit position can be negative
for invalid input such as gcc.dg/pr48335-8.c. */
HOST_WIDE_INT bitsize_;
HOST_WIDE_INT bitpos_;
HOST_WIDE_INT bitregion_start_;
HOST_WIDE_INT bitregion_end_;
unsigned int align_;
bool volatilep_;
int count_;
};
/* Find the best mode to use to access a bit field. */
extern enum machine_mode get_best_mode (int, int,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned int,
enum machine_mode, int);
enum machine_mode, bool);
/* Determine alignment, 1<=result<=BIGGEST_ALIGNMENT. */

View File

@ -2624,14 +2624,103 @@ fixup_unsigned_type (tree type)
layout_type (type);
}
/* Construct an iterator for a bitfield that spans BITSIZE bits,
starting at BITPOS.
BITREGION_START is the bit position of the first bit in this
sequence of bit fields. BITREGION_END is the last bit in this
sequence. If these two fields are non-zero, we should restrict the
memory access to that range. Otherwise, we are allowed to touch
any adjacent non bit-fields.
ALIGN is the alignment of the underlying object in bits.
VOLATILEP says whether the bitfield is volatile. */
bit_field_mode_iterator
::bit_field_mode_iterator (HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
HOST_WIDE_INT bitregion_start,
HOST_WIDE_INT bitregion_end,
unsigned int align, bool volatilep)
: mode_ (GET_CLASS_NARROWEST_MODE (MODE_INT)), bitsize_ (bitsize),
bitpos_ (bitpos), bitregion_start_ (bitregion_start),
bitregion_end_ (bitregion_end), align_ (MIN (align, BIGGEST_ALIGNMENT)),
volatilep_ (volatilep), count_ (0)
{
}
/* Calls to this function return successively larger modes that can be used
to represent the bitfield. Return true if another bitfield mode is
available, storing it in *OUT_MODE if so. */
bool
bit_field_mode_iterator::next_mode (enum machine_mode *out_mode)
{
for (; mode_ != VOIDmode; mode_ = GET_MODE_WIDER_MODE (mode_))
{
unsigned int unit = GET_MODE_BITSIZE (mode_);
/* Skip modes that don't have full precision. */
if (unit != GET_MODE_PRECISION (mode_))
continue;
/* Skip modes that are too small. */
if ((bitpos_ % unit) + bitsize_ > unit)
continue;
/* Stop if the mode is too wide to handle efficiently. */
if (unit > MAX_FIXED_MODE_SIZE)
break;
/* Don't deliver more than one multiword mode; the smallest one
should be used. */
if (count_ > 0 && unit > BITS_PER_WORD)
break;
/* Stop if the mode is wider than the alignment of the containing
object.
It is tempting to omit the following line unless STRICT_ALIGNMENT
is true. But that is incorrect, since if the bitfield uses part
of 3 bytes and we use a 4-byte mode, we could get a spurious segv
if the extra 4th byte is past the end of memory.
(Though at least one Unix compiler ignores this problem:
that on the Sequent 386 machine. */
if (unit > align_)
break;
/* Stop if the mode goes outside the bitregion. */
HOST_WIDE_INT start = bitpos_ - (bitpos_ % unit);
if (bitregion_start_ && start < bitregion_start_)
break;
if (bitregion_end_ && start + unit > bitregion_end_ + 1)
break;
*out_mode = mode_;
mode_ = GET_MODE_WIDER_MODE (mode_);
count_++;
return true;
}
return false;
}
/* Return true if smaller modes are generally preferred for this kind
of bitfield. */
bool
bit_field_mode_iterator::prefer_smaller_modes ()
{
return (volatilep_
? targetm.narrow_volatile_bitfield ()
: !SLOW_BYTE_ACCESS);
}
/* Find the best machine mode to use when referencing a bit field of length
BITSIZE bits starting at BITPOS.
BITREGION_START is the bit position of the first bit in this
sequence of bit fields. BITREGION_END is the last bit in this
sequence. If these two fields are non-zero, we should restrict the
memory access to a maximum sized chunk of
BITREGION_END - BITREGION_START + 1. Otherwise, we are allowed to touch
memory access to that range. Otherwise, we are allowed to touch
any adjacent non bit-fields.
The underlying object is known to be aligned to a boundary of ALIGN bits.
@ -2655,69 +2744,21 @@ get_best_mode (int bitsize, int bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
unsigned int align,
enum machine_mode largest_mode, int volatilep)
enum machine_mode largest_mode, bool volatilep)
{
bit_field_mode_iterator iter (bitsize, bitpos, bitregion_start,
bitregion_end, align, volatilep);
enum machine_mode widest_mode = VOIDmode;
enum machine_mode mode;
unsigned int unit = 0;
unsigned HOST_WIDE_INT maxbits;
/* If unset, no restriction. */
if (!bitregion_end)
maxbits = MAX_FIXED_MODE_SIZE;
else
maxbits = bitregion_end - bitregion_start + 1;
/* Find the narrowest integer mode that contains the bit field. */
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
while (iter.next_mode (&mode)
&& (largest_mode == VOIDmode
|| GET_MODE_SIZE (mode) <= GET_MODE_SIZE (largest_mode)))
{
unit = GET_MODE_BITSIZE (mode);
if (unit == GET_MODE_PRECISION (mode)
&& (bitpos % unit) + bitsize <= unit)
widest_mode = mode;
if (iter.prefer_smaller_modes ())
break;
}
if (mode == VOIDmode
/* It is tempting to omit the following line
if STRICT_ALIGNMENT is true.
But that is incorrect, since if the bitfield uses part of 3 bytes
and we use a 4-byte mode, we could get a spurious segv
if the extra 4th byte is past the end of memory.
(Though at least one Unix compiler ignores this problem:
that on the Sequent 386 machine. */
|| MIN (unit, BIGGEST_ALIGNMENT) > align
|| (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode))
|| unit > maxbits
|| (bitregion_end
&& bitpos - (bitpos % unit) + unit > bitregion_end + 1))
return VOIDmode;
if ((SLOW_BYTE_ACCESS && ! volatilep)
|| (volatilep && !targetm.narrow_volatile_bitfield ()))
{
enum machine_mode wide_mode = VOIDmode, tmode;
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT); tmode != VOIDmode;
tmode = GET_MODE_WIDER_MODE (tmode))
{
unit = GET_MODE_BITSIZE (tmode);
if (unit == GET_MODE_PRECISION (tmode)
&& bitpos / unit == (bitpos + bitsize - 1) / unit
&& unit <= BITS_PER_WORD
&& unit <= MIN (align, BIGGEST_ALIGNMENT)
&& unit <= maxbits
&& (largest_mode == VOIDmode
|| unit <= GET_MODE_BITSIZE (largest_mode))
&& (bitregion_end == 0
|| bitpos - (bitpos % unit) + unit <= bitregion_end + 1))
wide_mode = tmode;
}
if (wide_mode != VOIDmode)
return wide_mode;
}
return mode;
return widest_mode;
}
/* Gets minimal and maximal values for MODE (signed or unsigned depending on