OSDN Git Service

Backport from 2012-06-04 mainline r188172
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index cfa045b..bef833f 100644 (file)
@@ -550,16 +550,31 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        {
          /* 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 wordnum = (backwards
+                                 ? GET_MODE_SIZE (fieldmode) / UNITS_PER_WORD
+                                 - i - 1
+                                 : i);
          unsigned int bit_offset = (backwards
                                     ? MAX ((int) bitsize - ((int) i + 1)
                                            * BITS_PER_WORD,
                                            0)
                                     : (int) 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),
+         unsigned HOST_WIDE_INT new_bitsize =
+           MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
+
+         /* If the remaining chunk doesn't have full wordsize we have
+            to make sure that for big endian machines the higher order
+            bits are used.  */
+         if (new_bitsize < BITS_PER_WORD && BYTES_BIG_ENDIAN && !backwards)
+           value_word = simplify_expand_binop (word_mode, lshr_optab,
+                                               value_word,
+                                               GEN_INT (BITS_PER_WORD
+                                                        - new_bitsize),
+                                               NULL_RTX, true,
+                                               OPTAB_LIB_WIDEN);
+
+         if (!store_bit_field_1 (op0, new_bitsize,
                                  bitnum + bit_offset,
                                  bitregion_start, bitregion_end,
                                  word_mode,
@@ -816,8 +831,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   /* Under the C++0x memory model, we must not touch bits outside the
      bit region.  Adjust the address to start at the beginning of the
      bit region.  */
-  if (MEM_P (str_rtx)
-      && bitregion_start > 0)
+  if (MEM_P (str_rtx) && bitregion_start > 0)
     {
       enum machine_mode bestmode;
       enum machine_mode op_mode;
@@ -827,6 +841,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (op_mode == MAX_MACHINE_MODE)
        op_mode = VOIDmode;
 
+      gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0);
+
       offset = bitregion_start / BITS_PER_UNIT;
       bitnum -= bitregion_start;
       bitregion_end -= bitregion_start;
@@ -4216,10 +4232,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                        << (HOST_BITS_PER_WIDE_INT - 1)))
                          set_dst_reg_note (insn, REG_EQUAL,
                                            gen_rtx_DIV (compute_mode, op0,
-                                                        GEN_INT
-                                                          (trunc_int_for_mode
-                                                            (abs_d,
-                                                             compute_mode))),
+                                                        gen_int_mode
+                                                          (abs_d,
+                                                           compute_mode)),
                                            quotient);
 
                        quotient = expand_unop (compute_mode, neg_optab,