OSDN Git Service

Backport from mainline
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 6a9da64..077d0d7 100644 (file)
@@ -543,15 +543,17 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         is not allowed.  */
       fieldmode = GET_MODE (value);
       if (fieldmode == VOIDmode)
-       fieldmode = smallest_mode_for_size (nwords *
-                                           BITS_PER_WORD, MODE_INT);
+       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;
             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,
@@ -564,10 +566,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          /* 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)
-           value_word = extract_bit_field (value_word, new_bitsize, 0,
-                                           true, false, NULL_RTX,
-                                           BLKmode, word_mode);
+         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,
@@ -635,7 +640,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
           && flag_strict_volatile_bitfields > 0)
       && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
-           && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
+           && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
+      /* Do not use insv if the bit region is restricted and
+        op_mode integer at offset doesn't fit into the
+        restricted region.  */
+      && !(MEM_P (op0) && bitregion_end
+          && bitnum - bitpos + GET_MODE_BITSIZE (op_mode)
+             > bitregion_end + 1))
     {
       struct expand_operand ops[4];
       int xbitpos = bitpos;
@@ -755,7 +766,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits
          || (op_mode != MAX_MACHINE_MODE
              && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
-       bestmode = get_best_mode  (bitsize, bitnum,
+       bestmode = get_best_mode (bitsize, bitnum,
                                  bitregion_start, bitregion_end,
                                  MEM_ALIGN (op0),
                                  (op_mode == MAX_MACHINE_MODE
@@ -826,8 +837,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;
@@ -837,6 +847,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;
@@ -1090,6 +1102,16 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
       offset = (bitpos + bitsdone) / unit;
       thispos = (bitpos + bitsdone) % unit;
 
+      /* When region of bytes we can touch is restricted, decrease
+        UNIT close to the end of the region as needed.  */
+      if (bitregion_end
+         && unit > BITS_PER_UNIT
+         && bitpos + bitsdone - thispos + unit > bitregion_end + 1)
+       {
+         unit = unit / 2;
+         continue;
+       }
+
       /* THISSIZE must not overrun a word boundary.  Otherwise,
         store_fixed_bit_field will call us again, and we will mutually
         recurse forever.  */
@@ -2949,6 +2971,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
           && !optimize)
          ? target : 0;
       rtx accum_target = optimize ? 0 : accum;
+      rtx accum_inner;
 
       switch (alg->op[opno])
        {
@@ -3014,16 +3037,18 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
         that.  */
 
       tem = op0, nmode = mode;
+      accum_inner = accum;
       if (GET_CODE (accum) == SUBREG)
        {
-         nmode = GET_MODE (SUBREG_REG (accum));
+         accum_inner = SUBREG_REG (accum);
+         nmode = GET_MODE (accum_inner);
          tem = gen_lowpart (nmode, op0);
        }
 
       insn = get_last_insn ();
-      set_unique_reg_note (insn, REG_EQUAL,
-                          gen_rtx_MULT (nmode, tem,
-                                        GEN_INT (val_so_far)));
+      set_dst_reg_note (insn, REG_EQUAL,
+                       gen_rtx_MULT (nmode, tem, GEN_INT (val_so_far)),
+                       accum_inner);
     }
 
   if (variant == negate_variant)
@@ -3833,7 +3858,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
   rtx quotient = 0, remainder = 0;
   rtx last;
   int size;
-  rtx insn, set;
+  rtx insn;
   optab optab1, optab2;
   int op1_is_constant, op1_is_pow2 = 0;
   int max_cost, extra_cost;
@@ -4137,12 +4162,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                  break;
 
                insn = get_last_insn ();
-               if (insn != last
-                   && (set = single_set (insn)) != 0
-                   && SET_DEST (set) == quotient)
-                 set_unique_reg_note (insn,
-                                      REG_EQUAL,
-                                      gen_rtx_UDIV (compute_mode, op0, op1));
+               if (insn != last)
+                 set_dst_reg_note (insn, REG_EQUAL,
+                                   gen_rtx_UDIV (compute_mode, op0, op1),
+                                   quotient);
              }
            else                /* TRUNC_DIV, signed */
              {
@@ -4221,18 +4244,14 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      {
                        insn = get_last_insn ();
                        if (insn != last
-                           && (set = single_set (insn)) != 0
-                           && SET_DEST (set) == quotient
                            && abs_d < ((unsigned HOST_WIDE_INT) 1
                                        << (HOST_BITS_PER_WIDE_INT - 1)))
-                         set_unique_reg_note (insn,
-                                              REG_EQUAL,
-                                              gen_rtx_DIV (compute_mode,
-                                                           op0,
-                                                           GEN_INT
-                                                           (trunc_int_for_mode
-                                                            (abs_d,
-                                                             compute_mode))));
+                         set_dst_reg_note (insn, REG_EQUAL,
+                                           gen_rtx_DIV (compute_mode, op0,
+                                                        gen_int_mode
+                                                          (abs_d,
+                                                           compute_mode)),
+                                           quotient);
 
                        quotient = expand_unop (compute_mode, neg_optab,
                                                quotient, quotient, 0);
@@ -4319,12 +4338,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                  break;
 
                insn = get_last_insn ();
-               if (insn != last
-                   && (set = single_set (insn)) != 0
-                   && SET_DEST (set) == quotient)
-                 set_unique_reg_note (insn,
-                                      REG_EQUAL,
-                                      gen_rtx_DIV (compute_mode, op0, op1));
+               if (insn != last)
+                 set_dst_reg_note (insn, REG_EQUAL,
+                                   gen_rtx_DIV (compute_mode, op0, op1),
+                                   quotient);
              }
            break;
          }
@@ -4742,11 +4759,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                    NULL_RTX, 1);
 
            insn = get_last_insn ();
-           set_unique_reg_note (insn,
-                                REG_EQUAL,
-                                gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
-                                                compute_mode,
-                                                op0, op1));
+           set_dst_reg_note (insn, REG_EQUAL,
+                             gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
+                                             compute_mode, op0, op1),
+                             quotient);
          }
        break;