diff mbox

FIX PR51926, libstdc++ iterator store bigendian bitfield related

Message ID 20120121003710.GU3708@bubble.grove.modra.org
State New
Headers show

Commit Message

Alan Modra Jan. 21, 2012, 12:37 a.m. UTC
This patch fixes a wrong-code bug in store_bit_field.  When storing a
multi-word BLKmode value (such as from a RECORD_TYPE), the last word
is trashed on big-endian targets.  See the PR for the gory details.
Bootstrapped and regression tested powerpc64-linux.  Fixes 74
testsuite failures.  OK for mainline?  And earlier versions of gcc?

	PR middle-end/51926
	* expmed.c (store_bit_field_1): Properly handle last word of
	BLKmode value when bigendian.

Comments

Alan Modra Jan. 23, 2012, 9:23 a.m. UTC | #1
On Sat, Jan 21, 2012 at 11:07:10AM +1030, Alan Modra wrote:
> 	PR middle-end/51926
> 	* expmed.c (store_bit_field_1): Properly handle last word of
> 	BLKmode value when bigendian.

Blah, I was working on an old tree.  The bug is already fixed.
diff mbox

Patch

Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	(revision 183228)
+++ gcc/expmed.c	(working copy)
@@ -551,19 +551,27 @@  store_bit_field_1 (rtx str_rtx, unsigned
 	  /* If I is 0, use the low-order word in both field and target;
 	     if I is 1, use the next to lowest word; and so on.  */
 	  unsigned int wordnum = (backwards ? nwords - i - 1 : i);
+	  unsigned int nbits = (i == nwords - 1
+				? bitsize - i * BITS_PER_WORD
+				: BITS_PER_WORD);
 	  unsigned int bit_offset = (backwards
-				     ? MAX ((int) bitsize - ((int) i + 1)
-					    * BITS_PER_WORD,
-					    0)
-				     : (int) i * BITS_PER_WORD);
+				     ? bitsize - i * BITS_PER_WORD - nbits
+				     : i * BITS_PER_WORD);
 	  rtx value_word = operand_subword_force (value, wordnum, fieldmode);
 
-	  if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD,
-					    bitsize - i * BITS_PER_WORD),
-				  bitnum + bit_offset,
+	  if (WORDS_BIG_ENDIAN && !backwards && nbits != BITS_PER_WORD)
+	    {
+	      /* Original fieldmode was BLKmode.  The value in this
+		 case consists of bits in memory order, so any unused
+		 bits in the last word are in the least significant
+		 position.  */
+	      value_word = expand_shift (RSHIFT_EXPR, word_mode, value_word,
+					 BITS_PER_WORD - nbits,
+					 value_word, 1);
+	    }
+	  if (!store_bit_field_1 (op0, nbits, bitnum + bit_offset,
 				  bitregion_start, bitregion_end,
-				  word_mode,
-				  value_word, fallback_p))
+				  word_mode, value_word, fallback_p))
 	    {
 	      delete_insns_since (last);
 	      return false;