From 073a544dd99d1526bbf8906e8ac13d42a752d200 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 18 Nov 2012 17:33:01 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 9 +++ gcc/machmode.h | 25 ++++++- gcc/stor-layout.c | 161 +++++++++++++++++++++++++++++----------------- 3 files changed, 134 insertions(+), 61 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5d41ef9357a..d240dd5814a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2012-11-18 Richard Sandiford + + * 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 * expmed.c (narrow_bit_field_mem): New function. diff --git a/gcc/machmode.h b/gcc/machmode.h index b95d05b096e..f1c89cc8a63 100644 --- a/gcc/machmode.h +++ b/gcc/machmode.h @@ -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. */ diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 20c49f97041..b69c915c8ce 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -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