OSDN Git Service

PR target/36800
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 5e8d7f3..165bcae 100644 (file)
@@ -1,7 +1,7 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -532,6 +532,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       int icode = optab_handler (movstrict_optab, fieldmode)->insn_code;
       rtx insn;
       rtx start = get_last_insn ();
+      rtx arg0 = op0;
 
       /* Get appropriate low part of the value being stored.  */
       if (GET_CODE (value) == CONST_INT || REG_P (value))
@@ -552,11 +553,11 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          gcc_assert (GET_MODE (SUBREG_REG (op0)) == fieldmode
                      || GET_MODE_CLASS (fieldmode) == MODE_INT
                      || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
-         op0 = SUBREG_REG (op0);
+         arg0 = SUBREG_REG (op0);
        }
 
       insn = (GEN_FCN (icode)
-                (gen_rtx_SUBREG (fieldmode, op0,
+                (gen_rtx_SUBREG (fieldmode, arg0,
                                  (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
                                  + (offset * UNITS_PER_WORD)),
                                  value));
@@ -748,6 +749,16 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (pat)
        {
          emit_insn (pat);
+
+         /* If the mode of the insertion is wider than the mode of the
+            target register we created a paradoxical subreg for the
+            target.  Truncate the paradoxical subreg of the target to
+            itself properly.  */
+         if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (op0)),
+                                     GET_MODE_BITSIZE (op_mode))
+             && (REG_P (xop0)
+                 || GET_CODE (xop0) == SUBREG))
+             convert_move (op0, xop0, true);
          return true;
        }
       delete_insns_since (last);
@@ -1278,9 +1289,8 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       {
        if (MEM_P (op0))
          op0 = adjust_address (op0, imode, 0);
-       else
+       else if (imode != BLKmode)
          {
-           gcc_assert (imode != BLKmode);
            op0 = gen_lowpart (imode, op0);
 
            /* If we got a SUBREG, force it into a register since we
@@ -1288,6 +1298,24 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            if (GET_CODE (op0) == SUBREG)
              op0 = force_reg (imode, op0);
          }
+       else if (REG_P (op0))
+         {
+           rtx reg, subreg;
+           imode = smallest_mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
+                                           MODE_INT);
+           reg = gen_reg_rtx (imode);
+           subreg = gen_lowpart_SUBREG (GET_MODE (op0), reg);
+           emit_move_insn (subreg, op0);
+           op0 = reg;
+           bitnum += SUBREG_BYTE (subreg) * BITS_PER_UNIT;
+         }
+       else
+         {
+           rtx mem = assign_stack_temp (GET_MODE (op0),
+                                        GET_MODE_SIZE (GET_MODE (op0)), 0);
+           emit_move_insn (mem, op0);
+           op0 = adjust_address (mem, BLKmode, 0);
+         }
       }
   }
 
@@ -1516,7 +1544,13 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       if (GET_MODE (xtarget) != ext_mode)
        {
-         if (REG_P (xtarget))
+         /* Don't use LHS paradoxical subreg if explicit truncation is needed
+            between the mode of the extraction (word_mode) and the target
+            mode.  Instead, create a temporary and use convert_move to set
+            the target.  */
+         if (REG_P (xtarget)
+             && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (xtarget)),
+                                       GET_MODE_BITSIZE (ext_mode)))
            {
              xtarget = gen_lowpart (ext_mode, xtarget);
              if (GET_MODE_SIZE (ext_mode)
@@ -2102,7 +2136,8 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
        op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
                       % GET_MODE_BITSIZE (mode));
       else if (GET_CODE (op1) == SUBREG
-              && subreg_lowpart_p (op1))
+              && subreg_lowpart_p (op1)
+              && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (op1))))
        op1 = SUBREG_REG (op1);
     }
 
@@ -3963,10 +3998,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      {
                        /* Most significant bit of divisor is set; emit an scc
                           insn.  */
-                       quotient = emit_store_flag (tquotient, GEU, op0, op1,
-                                                   compute_mode, 1, 1);
-                       if (quotient == 0)
-                         goto fail1;
+                       quotient = emit_store_flag_force (tquotient, GEU, op0, op1,
+                                                         compute_mode, 1, 1);
                      }
                    else
                      {