OSDN Git Service

PR 31567
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index eae8093..cd530d0 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -151,7 +151,7 @@ static int is_aligning_offset (const_tree, const_tree);
 static void expand_operands (tree, tree, rtx, rtx*, rtx*,
                             enum expand_modifier);
 static rtx reduce_to_bit_field_precision (rtx, rtx, tree);
-static rtx do_store_flag (tree, rtx, enum machine_mode, int);
+static rtx do_store_flag (tree, rtx, enum machine_mode);
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn (enum machine_mode, rtx, tree);
 #endif
@@ -175,7 +175,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef MOVE_BY_PIECES_P
 #define MOVE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
-   < (unsigned int) MOVE_RATIO)
+   < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether clear_by_pieces should be
@@ -183,7 +183,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef CLEAR_BY_PIECES_P
 #define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) CLEAR_RATIO)
+   < (unsigned int) CLEAR_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
@@ -191,7 +191,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef SET_BY_PIECES_P
 #define SET_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) SET_RATIO)
+   < (unsigned int) SET_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
@@ -199,7 +199,7 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #ifndef STORE_BY_PIECES_P
 #define STORE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
-   < (unsigned int) MOVE_RATIO)
+   < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
 #endif
 
 /* This array records the insn_code of insns to perform block moves.  */
@@ -234,7 +234,6 @@ enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
 enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
 enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
 enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
-enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
 enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
 enum insn_code sync_lock_release[NUM_MACHINE_MODES];
 
@@ -588,27 +587,9 @@ convert_move (rtx to, rtx from, int unsignedp)
       if (unsignedp)
        fill_value = const0_rtx;
       else
-       {
-#ifdef HAVE_slt
-         if (HAVE_slt
-             && insn_data[(int) CODE_FOR_slt].operand[0].mode == word_mode
-             && STORE_FLAG_VALUE == -1)
-           {
-             emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
-                            lowpart_mode, 0);
-             fill_value = gen_reg_rtx (word_mode);
-             emit_insn (gen_slt (fill_value));
-           }
-         else
-#endif
-           {
-             fill_value
-               = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
-                               size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
-                               NULL_RTX, 0);
-             fill_value = convert_to_mode (word_mode, fill_value, 1);
-           }
-       }
+       fill_value = emit_store_flag (gen_reg_rtx (word_mode),
+                                     LT, lowfrom, const0_rtx,
+                                     VOIDmode, 0, -1);
 
       /* Fill the remaining words.  */
       for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
@@ -2039,10 +2020,55 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
       unsigned int bytelen = GET_MODE_SIZE (mode);
+      unsigned int adj_bytelen = bytelen;
       rtx dest = dst;
 
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
+       adj_bytelen = ssize - bytepos;
+
+      if (GET_CODE (dst) == CONCAT)
+       {
+         if (bytepos + adj_bytelen
+             <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           dest = XEXP (dst, 0);
+         else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           {
+             bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
+             dest = XEXP (dst, 1);
+           }
+         else
+           {
+             enum machine_mode dest_mode = GET_MODE (dest);
+             enum machine_mode tmp_mode = GET_MODE (tmps[i]);
+
+             gcc_assert (bytepos == 0 && XVECLEN (src, 0));
+
+             if (GET_MODE_ALIGNMENT (dest_mode)
+                 >= GET_MODE_ALIGNMENT (tmp_mode))
+               {
+                 dest = assign_stack_temp (dest_mode,
+                                           GET_MODE_SIZE (dest_mode),
+                                           0);
+                 emit_move_insn (adjust_address (dest,
+                                                 tmp_mode,
+                                                 bytepos),
+                                 tmps[i]);
+                 dst = dest;
+               }
+             else
+               {
+                 dest = assign_stack_temp (tmp_mode,
+                                           GET_MODE_SIZE (tmp_mode),
+                                           0);
+                 emit_move_insn (dest, tmps[i]);
+                 dst = adjust_address (dest, dest_mode, bytepos);
+               }
+             break;
+           }
+       }
+
+      if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
          /* store_bit_field always takes its value from the lsb.
             Move the fragment to the lsb if it's not already there.  */
@@ -2060,28 +2086,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
                                      build_int_cst (NULL_TREE, shift),
                                      tmps[i], 0);
            }
-         bytelen = ssize - bytepos;
-       }
-
-      if (GET_CODE (dst) == CONCAT)
-       {
-         if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
-           dest = XEXP (dst, 0);
-         else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
-           {
-             bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
-             dest = XEXP (dst, 1);
-           }
-         else
-           {
-             gcc_assert (bytepos == 0 && XVECLEN (src, 0));
-             dest = assign_stack_temp (GET_MODE (dest),
-                                       GET_MODE_SIZE (GET_MODE (dest)), 0);
-             emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
-                             tmps[i]);
-             dst = dest;
-             break;
-           }
+         bytelen = adj_bytelen;
        }
 
       /* Optimize the access just a bit.  */
@@ -2674,7 +2679,7 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
    for the function we use for block clears.  The first time FOR_CALL
    is true, we call assemble_external.  */
 
-static GTY(()) tree block_clear_fn;
+tree block_clear_fn;
 
 void
 init_block_clear_fn (const char *asmspec)
@@ -3439,13 +3444,14 @@ compress_float_constant (rtx x, rtx y)
   enum machine_mode srcmode;
   REAL_VALUE_TYPE r;
   int oldcost, newcost;
+  bool speed = optimize_insn_for_speed_p ();
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, y);
 
   if (LEGITIMATE_CONSTANT_P (y))
-    oldcost = rtx_cost (y, SET);
+    oldcost = rtx_cost (y, SET, speed);
   else
-    oldcost = rtx_cost (force_const_mem (dstmode, y), SET);
+    oldcost = rtx_cost (force_const_mem (dstmode, y), SET, speed);
 
   for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
        srcmode != orig_srcmode;
@@ -3472,7 +3478,7 @@ compress_float_constant (rtx x, rtx y)
          if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
            continue;
          /* This is valid, but may not be cheaper than the original. */
-         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
          if (oldcost < newcost)
            continue;
        }
@@ -3480,7 +3486,7 @@ compress_float_constant (rtx x, rtx y)
        {
          trunc_y = force_const_mem (srcmode, trunc_y);
          /* This is valid, but may not be cheaper than the original. */
-         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+         newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
          if (oldcost < newcost)
            continue;
          trunc_y = validize_mem (trunc_y);
@@ -4996,6 +5002,9 @@ count_type_elements (const_tree type, bool allow_flexarr)
     case REFERENCE_TYPE:
       return 1;
 
+    case ERROR_MARK:
+      return 0;
+
     case VOID_TYPE:
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -5551,6 +5560,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        HOST_WIDE_INT bitpos;
        rtvec vector = NULL;
        unsigned n_elts;
+       alias_set_type alias;
 
        gcc_assert (eltmode != BLKmode);
 
@@ -5602,7 +5612,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        if (need_to_clear && size > 0 && !vector)
          {
            if (REG_P (target))
-             emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+             emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
            else
              clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
@@ -5612,6 +5622,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        if (!cleared && !vector && REG_P (target))
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 
+        if (MEM_P (target))
+         alias = MEM_ALIAS_SET (target);
+       else
+         alias = get_alias_set (elttype);
+
         /* Store each element of the constructor into the corresponding
           element of TARGET, determined by counting the elements.  */
        for (idx = 0, i = 0;
@@ -5647,7 +5662,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                bitpos = eltpos * elt_size;
                store_constructor_field (target, bitsize, bitpos,
                                         value_mode, value, type,
-                                        cleared, get_alias_set (elttype));
+                                        cleared, alias);
              }
          }
 
@@ -6051,9 +6066,9 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return exp;
 }
 
-/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
-   look for whether EXP or any nested component-refs within EXP is marked
-   as PACKED.  */
+/* Given an expression EXP that may be a COMPONENT_REF, an ARRAY_REF or an
+   ARRAY_RANGE_REF, look for whether EXP or any nested component-refs within
+   EXP is marked as PACKED.  */
 
 bool
 contains_packed_reference (const_tree exp)
@@ -6093,7 +6108,7 @@ contains_packed_reference (const_tree exp)
 }
 
 /* Return a tree of sizetype representing the size, in bytes, of the element
-   of EXP, an ARRAY_REF.  */
+   of EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_element_size (tree exp)
@@ -6120,7 +6135,7 @@ array_ref_element_size (tree exp)
 }
 
 /* Return a tree representing the lower bound of the array mentioned in
-   EXP, an ARRAY_REF.  */
+   EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_low_bound (tree exp)
@@ -6141,7 +6156,7 @@ array_ref_low_bound (tree exp)
 }
 
 /* Return a tree representing the upper bound of the array mentioned in
-   EXP, an ARRAY_REF.  */
+   EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 
 tree
 array_ref_up_bound (tree exp)
@@ -6787,9 +6802,10 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
         CONSTRUCTORs too, which should yield a memory reference for the
         constructor's contents.  Assume language specific tree nodes can
         be expanded in some interesting way.  */
+      gcc_assert (TREE_CODE (exp) < LAST_AND_UNUSED_TREE_CODE);
       if (DECL_P (exp)
          || TREE_CODE (exp) == CONSTRUCTOR
-         || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
+         || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
        {
          result = expand_expr (exp, target, tmode,
                                modifier == EXPAND_INITIALIZER
@@ -6828,6 +6844,16 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
   gcc_assert (inner != exp);
 
   subtarget = offset || bitpos ? NULL_RTX : target;
+  /* For VIEW_CONVERT_EXPR, where the outer alignment is bigger than
+     inner alignment, force the inner to be sufficiently aligned.  */
+  if (CONSTANT_CLASS_P (inner)
+      && TYPE_ALIGN (TREE_TYPE (inner)) < TYPE_ALIGN (TREE_TYPE (exp)))
+    {
+      inner = copy_node (inner);
+      TREE_TYPE (inner) = copy_node (TREE_TYPE (inner));
+      TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp));
+      TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1;
+    }
   result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier);
 
   if (offset)
@@ -7134,7 +7160,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   unsignedp = TYPE_UNSIGNED (type);
 
   ignore = (target == const0_rtx
-           || ((code == NOP_EXPR || code == CONVERT_EXPR 
+           || ((CONVERT_EXPR_CODE_P (code)
                 || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
                && TREE_CODE (type) == VOID_TYPE));
 
@@ -7719,13 +7745,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case ARRAY_RANGE_REF:
     normal_inner_ref:
       {
-       enum machine_mode mode1;
+       enum machine_mode mode1, mode2;
        HOST_WIDE_INT bitsize, bitpos;
        tree offset;
-       int volatilep = 0;
+       int volatilep = 0, must_force_mem;
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
                                        &mode1, &unsignedp, &volatilep, true);
-       rtx orig_op0;
+       rtx orig_op0, memloc;
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
@@ -7735,7 +7761,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        /* If TEM's type is a union of variable size, pass TARGET to the inner
           computation, since it will need a temporary and TARGET is known
           to have to do.  This occurs in unchecked conversion in Ada.  */
-
        orig_op0 = op0
          = expand_expr (tem,
                         (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
@@ -7749,45 +7774,47 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          || modifier == EXPAND_STACK_PARM)
                         ? modifier : EXPAND_NORMAL);
 
-       /* If this is a constant, put it into a register if it is a legitimate
-          constant, OFFSET is 0, and we won't try to extract outside the
-          register (in case we were passed a partially uninitialized object
-          or a view_conversion to a larger size) or a BLKmode piece of it
-          (e.g. if it is unchecked-converted to a record type in Ada).  Force
-          the constant to memory otherwise.  */
-       if (CONSTANT_P (op0))
-         {
-           enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
-           if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0
-               && mode1 != BLKmode
-               && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
-             op0 = force_reg (mode, op0);
-           else
-             op0 = validize_mem (force_const_mem (mode, op0));
-         }
-
-       /* Otherwise, if this object not in memory and we either have an
-          offset, a BLKmode result, or a reference outside the object, put it
-          there.  Such cases can occur in Ada if we have unchecked conversion
-          of an expression from a scalar type to an array or record type or
-          for an ARRAY_RANGE_REF whose type is BLKmode.  */
-       else if (!MEM_P (op0)
-                && (offset != 0
-                    || mode1 == BLKmode
-                    || (bitpos + bitsize
-                        > GET_MODE_BITSIZE (GET_MODE (op0)))))
+       mode2
+         = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0);
+
+       /* If we have either an offset, a BLKmode result, or a reference
+          outside the underlying object, we must force it to memory.
+          Such a case can occur in Ada if we have unchecked conversion
+          of an expression from a scalar type to an aggregate type or
+          for an ARRAY_RANGE_REF whose type is BLKmode, or if we were
+          passed a partially uninitialized object or a view-conversion
+          to a larger size.  */
+       must_force_mem = (offset
+                         || mode1 == BLKmode
+                         || bitpos + bitsize > GET_MODE_BITSIZE (mode2));
+
+       /* If this is a constant, put it in a register if it is a legitimate
+          constant and we don't need a memory reference.  */
+       if (CONSTANT_P (op0)
+           && mode2 != BLKmode
+           && LEGITIMATE_CONSTANT_P (op0)
+           && !must_force_mem)
+         op0 = force_reg (mode2, op0);
+
+       /* Otherwise, if this is a constant, try to force it to the constant
+          pool.  Note that back-ends, e.g. MIPS, may refuse to do so if it
+          is a legitimate constant.  */
+       else if (CONSTANT_P (op0) && (memloc = force_const_mem (mode2, op0)))
+         op0 = validize_mem (memloc);
+
+       /* Otherwise, if this is a constant or the object is not in memory
+          and need be, put it there.  */
+       else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
          {
            tree nt = build_qualified_type (TREE_TYPE (tem),
                                            (TYPE_QUALS (TREE_TYPE (tem))
                                             | TYPE_QUAL_CONST));
-           rtx memloc = assign_temp (nt, 1, 1, 1);
-
+           memloc = assign_temp (nt, 1, 1, 1);
            emit_move_insn (memloc, op0);
            op0 = memloc;
          }
 
-       if (offset != 0)
+       if (offset)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
                                          EXPAND_SUM);
@@ -7944,20 +7971,20 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            if (mode == BLKmode)
              {
                HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
-               rtx new;
+               rtx new_rtx;
 
                /* If the reference doesn't use the alias set of its type,
                   we cannot create the temporary using that type.  */
                if (component_uses_parent_alias_set (exp))
                  {
-                   new = assign_stack_local (ext_mode, size, 0);
-                   set_mem_alias_set (new, get_alias_set (exp));
+                   new_rtx = assign_stack_local (ext_mode, size, 0);
+                   set_mem_alias_set (new_rtx, get_alias_set (exp));
                  }
                else
-                 new = assign_stack_temp_for_type (ext_mode, size, 0, type);
+                 new_rtx = assign_stack_temp_for_type (ext_mode, size, 0, type);
 
-               emit_move_insn (new, op0);
-               op0 = copy_rtx (new);
+               emit_move_insn (new_rtx, op0);
+               op0 = copy_rtx (new_rtx);
                PUT_MODE (op0, BLKmode);
                set_mem_attributes (op0, exp, 1);
              }
@@ -8016,18 +8043,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        if (fndecl
            && (attr = lookup_attribute ("warning",
                                         DECL_ATTRIBUTES (fndecl))) != NULL)
-         warning (0, "%Kcall to %qs declared with attribute warning: %s",
-                  exp, lang_hooks.decl_printable_name (fndecl, 1),
-                  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+         warning_at (tree_nonartificial_location (exp),
+                     0, "%Kcall to %qs declared with attribute warning: %s",
+                     exp, lang_hooks.decl_printable_name (fndecl, 1),
+                     TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
 
        /* Check for a built-in function.  */
        if (fndecl && DECL_BUILT_IN (fndecl))
          {
-           if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
-             return lang_hooks.expand_expr (exp, original_target,
-                                            tmode, modifier, alt_rtl);
-           else
-             return expand_builtin (exp, target, subtarget, tmode, ignore);
+           gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
+           return expand_builtin (exp, target, subtarget, tmode, ignore);
          }
       }
       return expand_call (exp, target, ignore);
@@ -8138,26 +8163,89 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return REDUCE_BIT_FIELD (op0);
 
     case VIEW_CONVERT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+      op0 = NULL_RTX;
+
+      /* If we are converting to BLKmode, try to avoid an intermediate
+        temporary by fetching an inner memory reference.  */
+      if (mode == BLKmode
+         && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
+         && TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != BLKmode
+         && handled_component_p (TREE_OPERAND (exp, 0)))
+      {
+       enum machine_mode mode1;
+       HOST_WIDE_INT bitsize, bitpos;
+       tree offset;
+       int unsignedp;
+       int volatilep = 0;
+       tree tem
+         = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, &bitpos,
+                                &offset, &mode1, &unsignedp, &volatilep,
+                                true);
+       rtx orig_op0;
+
+       /* ??? We should work harder and deal with non-zero offsets.  */
+       if (!offset
+           && (bitpos % BITS_PER_UNIT) == 0
+           && bitsize >= 0
+           && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) == 0)
+         {
+           /* See the normal_inner_ref case for the rationale.  */
+           orig_op0
+             = expand_expr (tem,
+                            (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                             && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                                 != INTEGER_CST)
+                             && modifier != EXPAND_STACK_PARM
+                             ? target : NULL_RTX),
+                            VOIDmode,
+                            (modifier == EXPAND_INITIALIZER
+                             || modifier == EXPAND_CONST_ADDRESS
+                             || modifier == EXPAND_STACK_PARM)
+                            ? modifier : EXPAND_NORMAL);
+
+           if (MEM_P (orig_op0))
+             {
+               op0 = orig_op0;
+
+               /* Get a reference to just this component.  */
+               if (modifier == EXPAND_CONST_ADDRESS
+                   || modifier == EXPAND_SUM
+                   || modifier == EXPAND_INITIALIZER)
+                 op0 = adjust_address_nv (op0, mode, bitpos / BITS_PER_UNIT);
+               else
+                 op0 = adjust_address (op0, mode, bitpos / BITS_PER_UNIT);
+
+               if (op0 == orig_op0)
+                 op0 = copy_rtx (op0);
+
+               set_mem_attributes (op0, TREE_OPERAND (exp, 0), 0);
+               if (REG_P (XEXP (op0, 0)))
+                 mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+
+               MEM_VOLATILE_P (op0) |= volatilep;
+             }
+         }
+      }
+
+      if (!op0)
+       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
 
       /* If the input and output modes are both the same, we are done.  */
-      if (TYPE_MODE (type) == GET_MODE (op0))
+      if (mode == GET_MODE (op0))
        ;
       /* If neither mode is BLKmode, and both modes are the same size
         then we can use gen_lowpart.  */
-      else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_SIZE (TYPE_MODE (type))
-                  == GET_MODE_SIZE (GET_MODE (op0)))
+      else if (mode != BLKmode && GET_MODE (op0) != BLKmode
+              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0)))
        {
          if (GET_CODE (op0) == SUBREG)
            op0 = force_reg (GET_MODE (op0), op0);
-         op0 = gen_lowpart (TYPE_MODE (type), op0);
+         op0 = gen_lowpart (mode, op0);
        }
       /* If both modes are integral, then we can convert from one to the
         other.  */
-      else if (SCALAR_INT_MODE_P (GET_MODE (op0))
-              && SCALAR_INT_MODE_P (TYPE_MODE (type)))
-       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
+      else if (SCALAR_INT_MODE_P (GET_MODE (op0)) && SCALAR_INT_MODE_P (mode))
+       op0 = convert_modes (mode, GET_MODE (op0), op0, 
                             TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       /* As a last resort, spill op0 to memory, and reload it in a
         different mode.  */
@@ -8181,8 +8269,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          op0 = target;
        }
 
-      /* At this point, OP0 is in the correct mode.  If the output type is such
-        that the operand is known to be aligned, indicate that it is.
+      /* At this point, OP0 is in the correct mode.  If the output type is
+        such that the operand is known to be aligned, indicate that it is.
         Otherwise, we need only be concerned about alignment for non-BLKmode
         results.  */
       if (MEM_P (op0))
@@ -8191,31 +8279,33 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
          if (TYPE_ALIGN_OK (type))
            set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
-         else if (TYPE_MODE (type) != BLKmode && STRICT_ALIGNMENT
-                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
+         else if (STRICT_ALIGNMENT
+                  && mode != BLKmode
+                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
            {
              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
              HOST_WIDE_INT temp_size
                = MAX (int_size_in_bytes (inner_type),
-                      (HOST_WIDE_INT) GET_MODE_SIZE (TYPE_MODE (type)));
-             rtx new = assign_stack_temp_for_type (TYPE_MODE (type),
-                                                   temp_size, 0, type);
-             rtx new_with_op0_mode = adjust_address (new, GET_MODE (op0), 0);
+                      (HOST_WIDE_INT) GET_MODE_SIZE (mode));
+             rtx new_rtx
+               = assign_stack_temp_for_type (mode, temp_size, 0, type);
+             rtx new_with_op0_mode
+               = adjust_address (new_rtx, GET_MODE (op0), 0);
 
              gcc_assert (!TREE_ADDRESSABLE (exp));
 
              if (GET_MODE (op0) == BLKmode)
                emit_block_move (new_with_op0_mode, op0,
-                                GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
+                                GEN_INT (GET_MODE_SIZE (mode)),
                                 (modifier == EXPAND_STACK_PARM
                                  ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
              else
                emit_move_insn (new_with_op0_mode, op0);
 
-             op0 = new;
+             op0 = new_rtx;
            }
 
-         op0 = adjust_address (op0, TYPE_MODE (type), 0);
+         op0 = adjust_address (op0, mode, 0);
        }
 
       return op0;
@@ -8224,6 +8314,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Even though the sizetype mode and the pointer's mode can be different
          expand is able to handle this correctly and get the correct result out 
          of the PLUS_EXPR code.  */
+      /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
+         if sizetype precision is smaller than pointer precision.  */
+      if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type))
+       exp = build2 (PLUS_EXPR, type,
+                     TREE_OPERAND (exp, 0),
+                     fold_convert (type,
+                                   fold_convert (ssizetype,
+                                                 TREE_OPERAND (exp, 1))));
     case PLUS_EXPR:
 
       /* Check if this is a case for multiplication and addition.  */
@@ -8925,7 +9023,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case LTGT_EXPR:
       temp = do_store_flag (exp,
                            modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
-                           tmode != VOIDmode ? tmode : mode, 0);
+                           tmode != VOIDmode ? tmode : mode);
       if (temp != 0)
        return temp;
 
@@ -8970,7 +9068,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* If no set-flag instruction, must generate a conditional store
         into a temporary variable.  Drop through and handle this
         like && and ||.  */
-
+      /* Although TRUTH_{AND,OR}IF_EXPR aren't present in GIMPLE, they
+        are occassionally created by folding during expansion.  */
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
       if (! ignore
          && (target == 0
              || modifier == EXPAND_STACK_PARM
@@ -9170,8 +9271,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case POSTDECREMENT_EXPR:
     case LOOP_EXPR:
     case EXIT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
@@ -9340,9 +9439,29 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
       goto binop;
 
+    case COMPOUND_LITERAL_EXPR:
+      {
+       /* Initialize the anonymous variable declared in the compound
+          literal, then return the variable.  */
+       tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
+
+       /* Create RTL for this variable.  */
+       if (!DECL_RTL_SET_P (decl))
+         {
+           if (DECL_HARD_REGISTER (decl))
+             /* The user specified an assembler name for this variable.
+                Set that up now.  */
+             rest_of_decl_compilation (decl, 0, 0);
+           else
+             expand_decl (decl);
+         }
+
+       return expand_expr_real (decl, original_target, tmode,
+                                modifier, alt_rtl);
+      }
+
     default:
-      return lang_hooks.expand_expr (exp, original_target, tmode,
-                                    modifier, alt_rtl);
+      gcc_unreachable ();
     }
 
   /* Here to do an ordinary binary operator.  */
@@ -9559,9 +9678,6 @@ string_constant (tree arg, tree *ptr_offset)
 
    If TARGET is nonzero, store the result there if convenient.
 
-   If ONLY_CHEAP is nonzero, only do this if it is likely to be very
-   cheap.
-
    Return zero if there is no suitable set-flag instruction
    available on this machine.
 
@@ -9574,7 +9690,7 @@ string_constant (tree arg, tree *ptr_offset)
    set/jump/set sequence.  */
 
 static rtx
-do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
+do_store_flag (tree exp, rtx target, enum machine_mode mode)
 {
   enum rtx_code code;
   tree arg0, arg1, type;
@@ -9583,7 +9699,6 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   int invert = 0;
   int unsignedp;
   rtx op0, op1;
-  enum insn_code icode;
   rtx subtarget = target;
   rtx result, label;
 
@@ -9727,37 +9842,6 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   if (! can_compare_p (code, operand_mode, ccp_store_flag))
     return 0;
 
-  icode = setcc_gen_code[(int) code];
-
-  if (icode == CODE_FOR_nothing)
-    {
-      enum machine_mode wmode;
-
-      for (wmode = operand_mode;
-          icode == CODE_FOR_nothing && wmode != VOIDmode;
-          wmode = GET_MODE_WIDER_MODE (wmode))
-       icode = optab_handler (cstore_optab, wmode)->insn_code;
-    }
-
-  if (icode == CODE_FOR_nothing
-      || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
-    {
-      /* We can only do this if it is one of the special cases that
-        can be handled without an scc insn.  */
-      if ((code == LT && integer_zerop (arg1))
-         || (! only_cheap && code == GE && integer_zerop (arg1)))
-       ;
-      else if (! only_cheap && (code == NE || code == EQ)
-              && TREE_CODE (type) != REAL_TYPE
-              && ((optab_handler (abs_optab, operand_mode)->insn_code
-                   != CODE_FOR_nothing)
-                  || (optab_handler (ffs_optab, operand_mode)->insn_code
-                      != CODE_FOR_nothing)))
-       ;
-      else
-       return 0;
-    }
-
   if (! get_subtarget (target)
       || GET_MODE (subtarget) != operand_mode)
     subtarget = 0;
@@ -9997,16 +10081,16 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
 int
 vector_mode_valid_p (enum machine_mode mode)
 {
-  enum mode_class class = GET_MODE_CLASS (mode);
+  enum mode_class mclass = GET_MODE_CLASS (mode);
   enum machine_mode innermode;
 
   /* Doh!  What's going on?  */
-  if (class != MODE_VECTOR_INT
-      && class != MODE_VECTOR_FLOAT
-      && class != MODE_VECTOR_FRACT
-      && class != MODE_VECTOR_UFRACT
-      && class != MODE_VECTOR_ACCUM
-      && class != MODE_VECTOR_UACCUM)
+  if (mclass != MODE_VECTOR_INT
+      && mclass != MODE_VECTOR_FLOAT
+      && mclass != MODE_VECTOR_FRACT
+      && mclass != MODE_VECTOR_UFRACT
+      && mclass != MODE_VECTOR_ACCUM
+      && mclass != MODE_VECTOR_UACCUM)
     return 0;
 
   /* Hardware support.  Woo hoo!  */