OSDN Git Service

PR middle-end/41123
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index cd530d0..6805cdc 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, 2008
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "df.h"
 #include "diagnostic.h"
+#include "ssaexpand.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -90,7 +91,7 @@ int cse_not_expected;
 
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
-struct move_by_pieces
+struct move_by_pieces_d
 {
   rtx to;
   rtx to_addr;
@@ -108,7 +109,7 @@ struct move_by_pieces
 /* This structure is used by store_by_pieces to describe the clear to
    be performed.  */
 
-struct store_by_pieces
+struct store_by_pieces_d
 {
   rtx to;
   rtx to_addr;
@@ -125,16 +126,16 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
                                                     unsigned int,
                                                     unsigned int);
 static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
-                             struct move_by_pieces *);
+                             struct move_by_pieces_d *);
 static bool block_move_libcall_safe_for_call_parm (void);
 static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
 static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
 static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
-static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
+static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
 static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
-                              struct store_by_pieces *);
+                              struct store_by_pieces_d *);
 static tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
@@ -267,7 +268,7 @@ init_expr_target (void)
   reg = gen_rtx_REG (VOIDmode, -1);
 
   insn = rtx_alloc (INSN);
-  pat = gen_rtx_SET (0, NULL_RTX, NULL_RTX);
+  pat = gen_rtx_SET (VOIDmode, NULL_RTX, NULL_RTX);
   PATTERN (insn) = pat;
 
   for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
@@ -771,7 +772,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
-      && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
+      && CONST_INT_P (x) && INTVAL (x) < 0)
     {
       HOST_WIDE_INT val = INTVAL (x);
 
@@ -792,7 +793,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
      non-volatile MEM.  Except for the constant case where MODE is no
      wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand.  */
 
-  if ((GET_CODE (x) == CONST_INT
+  if ((CONST_INT_P (x)
        && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_CLASS (oldmode) == MODE_INT
@@ -809,7 +810,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
       /* ?? If we don't know OLDMODE, we have to assume here that
         X does not need sign- or zero-extension.   This may not be
         the case, but it's the best we can do.  */
-      if (GET_CODE (x) == CONST_INT && oldmode != VOIDmode
+      if (CONST_INT_P (x) && oldmode != VOIDmode
          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode))
        {
          HOST_WIDE_INT val = INTVAL (x);
@@ -875,7 +876,7 @@ rtx
 move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
                unsigned int align, int endp)
 {
-  struct move_by_pieces data;
+  struct move_by_pieces_d data;
   rtx to_addr, from_addr = XEXP (from, 0);
   unsigned int max_size = MOVE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
@@ -1087,7 +1088,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
 
 static void
 move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
-                 struct move_by_pieces *data)
+                 struct move_by_pieces_d *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1 = NULL_RTX, from1;
@@ -1198,7 +1199,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
 
   /* Set MEM_SIZE as appropriate for this block copy.  The main place this
      can be incorrect is coming from __builtin_memcpy.  */
-  if (GET_CODE (size) == CONST_INT)
+  if (CONST_INT_P (size))
     {
       if (INTVAL (size) == 0)
        return 0;
@@ -1209,7 +1210,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
       set_mem_size (y, size);
     }
 
-  if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
+  if (CONST_INT_P (size) && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align, 0);
   else if (emit_block_move_via_movmem (x, y, size, align,
                                       expected_align, expected_size))
@@ -1312,7 +1313,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
             here because if SIZE is less than the mode mask, as it is
             returned by the macro, it will definitely be less than the
             actual mode mask.  */
-         && ((GET_CODE (size) == CONST_INT
+         && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
              || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
@@ -1423,7 +1424,7 @@ init_block_move_fn (const char *asmspec)
                                       const_ptr_type_node, sizetype,
                                       NULL_TREE);
 
-      fn = build_decl (FUNCTION_DECL, fn, args);
+      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
@@ -2248,6 +2249,26 @@ use_group_regs (rtx *call_fusage, rtx regs)
        use_reg (call_fusage, reg);
     }
 }
+
+/* Return the defining gimple statement for SSA_NAME NAME if it is an
+   assigment and the code of the expresion on the RHS is CODE.  Return
+   NULL otherwise.  */
+
+static gimple
+get_def_for_expr (tree name, enum tree_code code)
+{
+  gimple def_stmt;
+
+  if (TREE_CODE (name) != SSA_NAME)
+    return NULL;
+
+  def_stmt = get_gimple_for_ssa_name (name);
+  if (!def_stmt
+      || gimple_assign_rhs_code (def_stmt) != code)
+    return NULL;
+
+  return def_stmt;
+}
 \f
 
 /* Determine whether the LEN bytes generated by CONSTFUN can be
@@ -2361,7 +2382,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
                 rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
                 void *constfundata, unsigned int align, bool memsetp, int endp)
 {
-  struct store_by_pieces data;
+  struct store_by_pieces_d data;
 
   if (len == 0)
     {
@@ -2413,7 +2434,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
 static void
 clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
 {
-  struct store_by_pieces data;
+  struct store_by_pieces_d data;
 
   if (len == 0)
     return;
@@ -2441,7 +2462,7 @@ clear_by_pieces_1 (void *data ATTRIBUTE_UNUSED,
    rtx with BLKmode).  ALIGN is maximum alignment we can assume.  */
 
 static void
-store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
+store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
                   unsigned int align ATTRIBUTE_UNUSED)
 {
   rtx to_addr = XEXP (data->to, 0);
@@ -2539,7 +2560,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
 
 static void
 store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
-                  struct store_by_pieces *data)
+                  struct store_by_pieces_d *data)
 {
   unsigned int size = GET_MODE_SIZE (mode);
   rtx to1, cst;
@@ -2587,7 +2608,7 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
   /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
      just move a zero.  Otherwise, do this a piece at a time.  */
   if (mode != BLKmode
-      && GET_CODE (size) == CONST_INT
+      && CONST_INT_P (size)
       && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode))
     {
       rtx zero = CONST0_RTX (mode);
@@ -2614,7 +2635,7 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
 
   align = MEM_ALIGN (object);
 
-  if (GET_CODE (size) == CONST_INT
+  if (CONST_INT_P (size)
       && CLEAR_BY_PIECES_P (INTVAL (size), align))
     clear_by_pieces (object, INTVAL (size), align);
   else if (set_storage_via_setmem (object, size, const0_rtx, align,
@@ -2660,7 +2681,7 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
      for returning pointers, we could end up generating incorrect code.  */
 
   object_tree = make_tree (ptr_type_node, object);
-  if (GET_CODE (val) != CONST_INT)
+  if (!CONST_INT_P (val))
     val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
   size_tree = make_tree (sizetype, size);
   val_tree = make_tree (integer_type_node, val);
@@ -2693,7 +2714,7 @@ init_block_clear_fn (const char *asmspec)
                                       integer_type_node, sizetype,
                                       NULL_TREE);
 
-      fn = build_decl (FUNCTION_DECL, fn, args);
+      fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
@@ -2753,7 +2774,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
             BITS_PER_HOST_WIDE_INT here because if SIZE is less than
             the mode mask, as it is returned by the macro, it will
             definitely be less than the actual mode mask.  */
-         && ((GET_CODE (size) == CONST_INT
+         && ((CONST_INT_P (size)
               && ((unsigned HOST_WIDE_INT) INTVAL (size)
                   <= (GET_MODE_MASK (mode) >> 1)))
              || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
@@ -3025,7 +3046,7 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
       HOST_WIDE_INT val;
 
       gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
-      gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+      gcc_assert (CONST_INT_P (XEXP (expr, 1)));
       val = INTVAL (XEXP (expr, 1));
       if (GET_CODE (expr) == MINUS)
        val = -val;
@@ -3551,7 +3572,7 @@ push_block (rtx size, int extra, int below)
     }
   else
     {
-      if (GET_CODE (size) == CONST_INT)
+      if (CONST_INT_P (size))
        temp = plus_constant (virtual_outgoing_args_rtx,
                              -INTVAL (size) - (below ? 0 : extra));
       else if (extra != 0 && !below)
@@ -3762,7 +3783,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
         on the stack for alignment purposes.  */
       if (args_addr == 0
          && PUSH_ARGS
-         && GET_CODE (size) == CONST_INT
+         && CONST_INT_P (size)
          && skip == 0
          && MEM_ALIGN (xinner) >= align
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
@@ -3795,7 +3816,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
          /* Deduct words put into registers from the size we must copy.  */
          if (partial != 0)
            {
-             if (GET_CODE (size) == CONST_INT)
+             if (CONST_INT_P (size))
                size = GEN_INT (INTVAL (size) - used);
              else
                size = expand_binop (GET_MODE (size), sub_optab, size,
@@ -3811,7 +3832,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
              temp = push_block (size, extra, where_pad == downward);
              extra = 0;
            }
-         else if (GET_CODE (args_so_far) == CONST_INT)
+         else if (CONST_INT_P (args_so_far))
            temp = memory_address (BLKmode,
                                   plus_constant (args_addr,
                                                  skip + INTVAL (args_so_far)));
@@ -3927,7 +3948,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       else
 #endif
        {
-         if (GET_CODE (args_so_far) == CONST_INT)
+         if (CONST_INT_P (args_so_far))
            addr
              = memory_address (mode,
                                plus_constant (args_addr,
@@ -4229,7 +4250,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
       /* Handle expand_expr of a complex value returning a CONCAT.  */
       if (GET_CODE (to_rtx) == CONCAT)
        {
-         if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
+         if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))))
            {
              gcc_assert (bitpos == 0);
              result = store_expr (from, to_rtx, false, nontemporal);
@@ -4275,6 +4296,36 @@ expand_assignment (tree to, tree from, bool nontemporal)
       return;
     }
 
+   else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
+     {
+       enum machine_mode mode, op_mode1;
+       enum insn_code icode;
+       rtx reg, addr, mem, insn;
+
+       reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+       reg = force_not_mem (reg);
+
+       mode = TYPE_MODE (TREE_TYPE (to));
+       addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode,
+                         EXPAND_SUM);
+       addr = memory_address (mode, addr);
+       mem = gen_rtx_MEM (mode, addr);
+
+       set_mem_attributes (mem, to, 0);
+
+       icode = movmisalign_optab->handlers[mode].insn_code;
+       gcc_assert (icode != CODE_FOR_nothing);
+
+       op_mode1 = insn_data[icode].operand[1].mode;
+       if (! (*insn_data[icode].operand[1].predicate) (reg, op_mode1)
+           && op_mode1 != VOIDmode)
+         reg = copy_to_mode_reg (op_mode1, reg);
+
+      insn = GEN_FCN (icode) (mem, reg);
+       emit_insn (insn);
+       return;
+     }
+
   /* If the rhs is a function call and its value is not an aggregate,
      call the function before we start to compute the lhs.
      This is needed for correct code for cases such as
@@ -4284,12 +4335,13 @@ expand_assignment (tree to, tree from, bool nontemporal)
      Don't do this if TO is a VAR_DECL or PARM_DECL whose DECL_RTL is REG
      since it might be a promoted variable where the zero- or sign- extension
      needs to be done.  Handling this in the normal way is safe because no
-     computation is done before the call.  */
+     computation is done before the call.  The same is true for SSA names.  */
   if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
       && COMPLETE_TYPE_P (TREE_TYPE (from))
       && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
-      && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
-           && REG_P (DECL_RTL (to))))
+      && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
+            && REG_P (DECL_RTL (to)))
+           || TREE_CODE (to) == SSA_NAME))
     {
       rtx value;
 
@@ -4434,6 +4486,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
   rtx temp;
   rtx alt_rtl = NULL_RTX;
   int dont_return_target = 0;
+  location_t loc = EXPR_LOCATION (exp);
 
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     {
@@ -4509,13 +4562,13 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
                  (TYPE_MODE (TREE_TYPE (exp)),
                   SUBREG_PROMOTED_UNSIGNED_P (target));
 
-             exp = fold_convert (ntype, exp);
+             exp = fold_convert_loc (loc, ntype, exp);
            }
 
-         exp = fold_convert (lang_hooks.types.type_for_mode
-                               (GET_MODE (SUBREG_REG (target)),
-                                SUBREG_PROMOTED_UNSIGNED_P (target)),
-                             exp);
+         exp = fold_convert_loc (loc, lang_hooks.types.type_for_mode
+                                 (GET_MODE (SUBREG_REG (target)),
+                                  SUBREG_PROMOTED_UNSIGNED_P (target)),
+                                 exp);
 
          inner_target = SUBREG_REG (target);
        }
@@ -4680,7 +4733,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
             type of the string, which is actually the size of the target.  */
          rtx size = expr_size (exp);
 
-         if (GET_CODE (size) == CONST_INT
+         if (CONST_INT_P (size)
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
            emit_block_move (target, temp, size,
                             (call_param_p
@@ -4689,9 +4742,9 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
            {
              /* Compute the size of the data to copy from the string.  */
              tree copy_size
-               = size_binop (MIN_EXPR,
-                             make_tree (sizetype, size),
-                             size_int (TREE_STRING_LENGTH (exp)));
+               = size_binop_loc (loc, MIN_EXPR,
+                                 make_tree (sizetype, size),
+                                 size_int (TREE_STRING_LENGTH (exp)));
              rtx copy_size_rtx
                = expand_expr (copy_size, NULL_RTX, VOIDmode,
                               (call_param_p
@@ -4707,7 +4760,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 
              /* Figure out how much is left in TARGET that we have to clear.
                 Do all calculations in ptr_mode.  */
-             if (GET_CODE (copy_size_rtx) == CONST_INT)
+             if (CONST_INT_P (copy_size_rtx))
                {
                  size = plus_constant (size, -INTVAL (copy_size_rtx));
                  target = adjust_address (target, BLKmode,
@@ -5382,13 +5435,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            enum machine_mode mode;
            HOST_WIDE_INT bitsize;
            HOST_WIDE_INT bitpos;
-           int unsignedp;
            rtx xtarget = target;
 
            if (cleared && initializer_zerop (value))
              continue;
 
-           unsignedp = TYPE_UNSIGNED (elttype);
            mode = TYPE_MODE (elttype);
            if (mode == BLKmode)
              bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
@@ -5444,13 +5495,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    tree exit_cond;
 
                    expand_normal (hi_index);
-                   unsignedp = TYPE_UNSIGNED (domain);
-
-                   index = build_decl (VAR_DECL, NULL_TREE, domain);
 
-                   index_r
-                     = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
-                                                  &unsignedp, 0));
+                   index = build_decl (EXPR_LOCATION (exp),
+                                       VAR_DECL, NULL_TREE, domain);
+                   index_r = gen_reg_rtx (promote_decl_mode (index, NULL));
                    SET_DECL_RTL (index, index_r);
                    store_expr (lo_index, index_r, 0, false);
 
@@ -5774,22 +5822,25 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
     {
       rtx temp;
+      gimple nop_def;
 
       /* If EXP is a NOP_EXPR of precision less than its mode, then that
         implies a mask operation.  If the precision is the same size as
         the field we're storing into, that mask is redundant.  This is
         particularly common with bit field assignments generated by the
         C front end.  */
-      if (TREE_CODE (exp) == NOP_EXPR)
+      nop_def = get_def_for_expr (exp, NOP_EXPR);
+      if (nop_def)
        {
          tree type = TREE_TYPE (exp);
          if (INTEGRAL_TYPE_P (type)
              && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type))
              && bitsize == TYPE_PRECISION (type))
            {
-             type = TREE_TYPE (TREE_OPERAND (exp, 0));
+             tree op = gimple_assign_rhs1 (nop_def);
+             type = TREE_TYPE (op);
              if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize)
-               exp = TREE_OPERAND (exp, 0);
+               exp = op;
            }
        }
 
@@ -6115,6 +6166,7 @@ array_ref_element_size (tree exp)
 {
   tree aligned_size = TREE_OPERAND (exp, 3);
   tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+  location_t loc = EXPR_LOCATION (exp);
 
   /* If a size was specified in the ARRAY_REF, it's the size measured
      in alignment units of the element type.  So multiply by that value.  */
@@ -6123,9 +6175,9 @@ array_ref_element_size (tree exp)
       /* ??? tree_ssa_useless_type_conversion will eliminate casts to
         sizetype from another type of the same width and signedness.  */
       if (TREE_TYPE (aligned_size) != sizetype)
-       aligned_size = fold_convert (sizetype, aligned_size);
-      return size_binop (MULT_EXPR, aligned_size,
-                        size_int (TYPE_ALIGN_UNIT (elmt_type)));
+       aligned_size = fold_convert_loc (loc, sizetype, aligned_size);
+      return size_binop_loc (loc, MULT_EXPR, aligned_size,
+                            size_int (TYPE_ALIGN_UNIT (elmt_type)));
     }
 
   /* Otherwise, take the size from that of the element type.  Substitute
@@ -6180,6 +6232,7 @@ component_ref_field_offset (tree exp)
 {
   tree aligned_offset = TREE_OPERAND (exp, 2);
   tree field = TREE_OPERAND (exp, 1);
+  location_t loc = EXPR_LOCATION (exp);
 
   /* If an offset was specified in the COMPONENT_REF, it's the offset measured
      in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  So multiply by that
@@ -6189,9 +6242,10 @@ component_ref_field_offset (tree exp)
       /* ??? tree_ssa_useless_type_conversion will eliminate casts to
         sizetype from another type of the same width and signedness.  */
       if (TREE_TYPE (aligned_offset) != sizetype)
-       aligned_offset = fold_convert (sizetype, aligned_offset);
-      return size_binop (MULT_EXPR, aligned_offset,
-                        size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+       aligned_offset = fold_convert_loc (loc, sizetype, aligned_offset);
+      return size_binop_loc (loc, MULT_EXPR, aligned_offset,
+                            size_int (DECL_OFFSET_ALIGN (field)
+                                      / BITS_PER_UNIT));
     }
 
   /* Otherwise, take the offset from that of the field.  Substitute
@@ -6200,26 +6254,44 @@ component_ref_field_offset (tree exp)
     return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
 }
 
-/* Return 1 if T is an expression that get_inner_reference handles.  */
+/* Alignment in bits the TARGET of an assignment may be assumed to have.  */
 
-int
-handled_component_p (const_tree t)
+static unsigned HOST_WIDE_INT
+target_align (const_tree target)
 {
-  switch (TREE_CODE (t))
+  /* We might have a chain of nested references with intermediate misaligning
+     bitfields components, so need to recurse to find out.  */
+
+  unsigned HOST_WIDE_INT this_align, outer_align;
+
+  switch (TREE_CODE (target))
     {
     case BIT_FIELD_REF:
+      return 1;
+
     case COMPONENT_REF:
+      this_align = DECL_ALIGN (TREE_OPERAND (target, 1));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MIN (this_align, outer_align);
+
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
+      this_align = TYPE_ALIGN (TREE_TYPE (target));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MIN (this_align, outer_align);
+
+    CASE_CONVERT:
+    case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      return 1;
+      this_align = TYPE_ALIGN (TREE_TYPE (target));
+      outer_align = target_align (TREE_OPERAND (target, 0));
+      return MAX (this_align, outer_align);
 
     default:
-      return 0;
+      return TYPE_ALIGN (TREE_TYPE (target));
     }
 }
+
 \f
 /* Given an rtx VALUE that may contain additions and multiplications, return
    an equivalent value that just refers to a register, memory, or constant.
@@ -6269,7 +6341,7 @@ force_operand (rtx value, rtx target)
       op2 = XEXP (value, 1);
       if (!CONSTANT_P (op2) && !(REG_P (op2) && op2 != subtarget))
        subtarget = 0;
-      if (code == MINUS && GET_CODE (op2) == CONST_INT)
+      if (code == MINUS && CONST_INT_P (op2))
        {
          code = PLUS;
          op2 = negate_rtx (GET_MODE (value), op2);
@@ -6281,7 +6353,7 @@ force_operand (rtx value, rtx target)
          constant first and then add the other value.  This allows virtual
          register instantiation to simply modify the constant rather than
          creating another one around this addition.  */
-      if (code == PLUS && GET_CODE (op2) == CONST_INT
+      if (code == PLUS && CONST_INT_P (op2)
          && GET_CODE (XEXP (value, 0)) == PLUS
          && REG_P (XEXP (XEXP (value, 0), 0))
          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
@@ -6666,14 +6738,10 @@ highest_pow2_factor (const_tree exp)
 static unsigned HOST_WIDE_INT
 highest_pow2_factor_for_target (const_tree target, const_tree exp)
 {
-  unsigned HOST_WIDE_INT target_align, factor;
-
-  factor = highest_pow2_factor (exp);
-  if (TREE_CODE (target) == COMPONENT_REF)
-    target_align = DECL_ALIGN_UNIT (TREE_OPERAND (target, 1));
-  else
-    target_align = TYPE_ALIGN_UNIT (TREE_TYPE (target));
-  return MAX (factor, target_align);
+  unsigned HOST_WIDE_INT talign = target_align (target) / BITS_PER_UNIT;
+  unsigned HOST_WIDE_INT factor = highest_pow2_factor (exp);
+  
+  return MAX (factor, talign);
 }
 \f
 /* Return &VAR expression for emulated thread local VAR.  */
@@ -6685,7 +6753,7 @@ emutls_var_address (tree var)
   tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
   tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
   tree arglist = build_tree_list (NULL_TREE, arg);
-  tree call = build_function_call_expr (fn, arglist);
+  tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
   return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
 }
 \f
@@ -7149,6 +7217,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   int ignore;
   tree context, subexp0, subexp1;
   bool reduce_bit_field;
+  gimple subexp0_def, subexp1_def;
+  tree top0, top1;
+  location_t loc = EXPR_LOCATION (exp);
 #define REDUCE_BIT_FIELD(expr) (reduce_bit_field                         \
                                 ? reduce_to_bit_field_precision ((expr), \
                                                                  target, \
@@ -7244,8 +7315,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       }
 
     case SSA_NAME:
-      return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
-                                NULL);
+      /* ??? ivopts calls expander, without any preparation from
+         out-of-ssa.  So fake instructions as if this was an access to the
+        base variable.  This unnecessarily allocates a pseudo, see how we can
+        reuse it, if partition base vars have it set already.  */
+      if (!currently_expanding_to_rtl)
+       return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, NULL);
+      {
+       gimple g = get_gimple_for_ssa_name (exp);
+       if (g)
+         return expand_expr_real_1 (gimple_assign_rhs_to_tree (g), target,
+                                    tmode, modifier, NULL);
+      }
+      decl_rtl = get_rtx_for_ssa_name (exp);
+      exp = SSA_NAME_VAR (exp);
+      goto expand_decl_rtl;
 
     case PARM_DECL:
     case VAR_DECL:
@@ -7262,7 +7346,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          && TREE_CODE (exp) == VAR_DECL
          && DECL_THREAD_LOCAL_P (exp))
        {
-         exp = build_fold_indirect_ref (emutls_var_address (exp));
+         exp = build_fold_indirect_ref_loc (loc, emutls_var_address (exp));
          return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
        }
 
@@ -7271,6 +7355,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case FUNCTION_DECL:
     case RESULT_DECL:
       decl_rtl = DECL_RTL (exp);
+    expand_decl_rtl:
       gcc_assert (decl_rtl);
       decl_rtl = copy_rtx (decl_rtl);
 
@@ -7338,9 +7423,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
-         pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
-                               (TREE_CODE (exp) == RESULT_DECL
-                                || TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
+         pmode = promote_decl_mode (exp, &unsignedp);
          gcc_assert (GET_MODE (decl_rtl) == pmode);
 
          temp = gen_lowpart_SUBREG (mode, decl_rtl);
@@ -7371,7 +7454,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          {
            tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
            if (type_for_mode)
-             tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp);
+             tmp = fold_unary_loc (loc, VIEW_CONVERT_EXPR, type_for_mode, exp);
          }
        if (!tmp)
          tmp = build_constructor_from_list (type,
@@ -7452,7 +7535,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
               with non-BLKmode values.  */
            gcc_assert (GET_MODE (ret) != BLKmode);
 
-           val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
+           val = build_decl (EXPR_LOCATION (exp),
+                             VAR_DECL, NULL, TREE_TYPE (exp));
            DECL_ARTIFICIAL (val) = 1;
            DECL_IGNORED_P (val) = 1;
            TREE_OPERAND (exp, 0) = val;
@@ -7520,9 +7604,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        /* Resolve the misalignment now, so that we don't have to remember
           to resolve it later.  Of course, this only works for reads.  */
-       /* ??? When we get around to supporting writes, we'll have to handle
-          this in store_expr directly.  The vectorizer isn't generating
-          those yet, however.  */
        if (code == MISALIGNED_INDIRECT_REF)
          {
            int icode;
@@ -7654,7 +7735,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                  {
                    tree index1 = index;
                    tree low_bound = array_ref_low_bound (exp);
-                   index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
+                   index1 = fold_convert_loc (loc, sizetype,
+                                              TREE_OPERAND (exp, 1));
 
                    /* Optimize the special-case of a zero lower bound.
 
@@ -7665,8 +7747,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
 
                    if (! integer_zerop (low_bound))
-                     index1 = size_diffop (index1, fold_convert (sizetype,
-                                                                 low_bound));
+                     index1 = size_diffop_loc (loc, index1,
+                                           fold_convert_loc (loc, sizetype,
+                                                             low_bound));
 
                    if (0 > compare_tree_int (index1,
                                              TREE_STRING_LENGTH (init)))
@@ -7788,6 +7871,33 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          || mode1 == BLKmode
                          || bitpos + bitsize > GET_MODE_BITSIZE (mode2));
 
+       /* Handle CONCAT first.  */
+       if (GET_CODE (op0) == CONCAT && !must_force_mem)
+         {
+           if (bitpos == 0
+               && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+             return op0;
+           if (bitpos == 0
+               && bitsize == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
+               && bitsize)
+             {
+               op0 = XEXP (op0, 0);
+               mode2 = GET_MODE (op0);
+             }
+           else if (bitpos == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
+                    && bitsize == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 1)))
+                    && bitpos
+                    && bitsize)
+             {
+               op0 = XEXP (op0, 1);
+               bitpos = 0;
+               mode2 = GET_MODE (op0);
+             }
+           else
+             /* Otherwise force into memory.  */
+             must_force_mem = 1;
+         }
+
        /* 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)
@@ -7861,16 +7971,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            MEM_VOLATILE_P (op0) = 1;
          }
 
-       /* The following code doesn't handle CONCAT.
-          Assume only bitpos == 0 can be used for CONCAT, due to
-          one element arrays having the same mode as its element.  */
-       if (GET_CODE (op0) == CONCAT)
-         {
-           gcc_assert (bitpos == 0
-                       && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)));
-           return op0;
-         }
-
        /* In cases where an aligned union has an unaligned object
           as a field, we might be extracting a BLKmode value from
           an integer-mode (e.g., SImode) object.  Handle this case
@@ -8038,14 +8138,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            && (attr = lookup_attribute ("error",
                                         DECL_ATTRIBUTES (fndecl))) != NULL)
          error ("%Kcall to %qs declared with attribute error: %s",
-                exp, lang_hooks.decl_printable_name (fndecl, 1),
+                exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
                 TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
        if (fndecl
            && (attr = lookup_attribute ("warning",
                                         DECL_ATTRIBUTES (fndecl))) != NULL)
          warning_at (tree_nonartificial_location (exp),
                      0, "%Kcall to %qs declared with attribute warning: %s",
-                     exp, lang_hooks.decl_printable_name (fndecl, 1),
+                     exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
                      TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
 
        /* Check for a built-in function.  */
@@ -8228,7 +8328,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       }
 
       if (!op0)
-       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+       op0 = expand_expr (TREE_OPERAND (exp, 0),
+                          NULL_RTX, VOIDmode, modifier);
 
       /* If the input and output modes are both the same, we are done.  */
       if (mode == GET_MODE (op0))
@@ -8236,7 +8337,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* If neither mode is BLKmode, and both modes are the same size
         then we can use gen_lowpart.  */
       else if (mode != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0)))
+              && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0))
+              && !COMPLEX_MODE_P (GET_MODE (op0)))
        {
          if (GET_CODE (op0) == SUBREG)
            op0 = force_reg (GET_MODE (op0), op0);
@@ -8317,37 +8419,41 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* 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))));
+       exp
+         = build2 (PLUS_EXPR, type,
+                   TREE_OPERAND (exp, 0),
+                   fold_convert_loc (loc, type,
+                                     fold_convert_loc (loc, ssizetype,
+                                                       TREE_OPERAND (exp, 1))));
     case PLUS_EXPR:
 
       /* Check if this is a case for multiplication and addition.  */
       if ((TREE_CODE (type) == INTEGER_TYPE
           || TREE_CODE (type) == FIXED_POINT_TYPE)
-         && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
+         && (subexp0_def = get_def_for_expr (TREE_OPERAND (exp, 0),
+                                             MULT_EXPR)))
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1, this_code;
+         gimple subsubexp0_def, subsubexp1_def;
+         enum tree_code this_code;
 
-         subexp0 = TREE_OPERAND (exp, 0);
-         subsubexp0 = TREE_OPERAND (subexp0, 0);
-         subsubexp1 = TREE_OPERAND (subexp0, 1);
-         code0 = TREE_CODE (subsubexp0);
-         code1 = TREE_CODE (subsubexp1);
          this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
                                                       : FIXED_CONVERT_EXPR;
-         if (code0 == this_code && code1 == this_code
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+         subsubexp0 = gimple_assign_rhs1 (subexp0_def);
+         subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
+         subsubexp1 = gimple_assign_rhs2 (subexp0_def);
+         subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
+         if (subsubexp0_def && subsubexp1_def
+             && (top0 = gimple_assign_rhs1 (subsubexp0_def))
+             && (top1 = gimple_assign_rhs1 (subsubexp1_def))
+             && (TYPE_PRECISION (TREE_TYPE (top0))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
-             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+             && (TYPE_PRECISION (TREE_TYPE (top0))
+                 == TYPE_PRECISION (TREE_TYPE (top1)))
+             && (TYPE_UNSIGNED (TREE_TYPE (top0))
+                 == TYPE_UNSIGNED (TREE_TYPE (top1))))
            {
-             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+             tree op0type = TREE_TYPE (top0);
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
              bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
@@ -8360,9 +8466,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                  && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
                {
-                 expand_operands (TREE_OPERAND (subsubexp0, 0),
-                                  TREE_OPERAND (subsubexp1, 0),
-                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                 expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+                                  EXPAND_NORMAL);
                  op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget,
                                     VOIDmode, EXPAND_NORMAL);
                  temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
@@ -8474,7 +8579,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          || mode != ptr_mode)
        {
          expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                          subtarget, &op0, &op1, 0);
+                          subtarget, &op0, &op1, EXPAND_NORMAL);
          if (op0 == const0_rtx)
            return op1;
          if (op1 == const0_rtx)
@@ -8490,27 +8595,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Check if this is a case for multiplication and subtraction.  */
       if ((TREE_CODE (type) == INTEGER_TYPE
           || TREE_CODE (type) == FIXED_POINT_TYPE)
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+         && (subexp1_def = get_def_for_expr (TREE_OPERAND (exp, 1),
+                                             MULT_EXPR)))
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1, this_code;
+         gimple subsubexp0_def, subsubexp1_def;
+         enum tree_code this_code;
 
-         subexp1 = TREE_OPERAND (exp, 1);
-         subsubexp0 = TREE_OPERAND (subexp1, 0);
-         subsubexp1 = TREE_OPERAND (subexp1, 1);
-         code0 = TREE_CODE (subsubexp0);
-         code1 = TREE_CODE (subsubexp1);
          this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
                                                       : FIXED_CONVERT_EXPR;
-         if (code0 == this_code && code1 == this_code
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+         subsubexp0 = gimple_assign_rhs1 (subexp1_def);
+         subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
+         subsubexp1 = gimple_assign_rhs2 (subexp1_def);
+         subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
+         if (subsubexp0_def && subsubexp1_def
+             && (top0 = gimple_assign_rhs1 (subsubexp0_def))
+             && (top1 = gimple_assign_rhs1 (subsubexp1_def))
+             && (TYPE_PRECISION (TREE_TYPE (top0))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
-             && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
-             && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
-                 == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+             && (TYPE_PRECISION (TREE_TYPE (top0))
+                 == TYPE_PRECISION (TREE_TYPE (top1)))
+             && (TYPE_UNSIGNED (TREE_TYPE (top0))
+                 == TYPE_UNSIGNED (TREE_TYPE (top1))))
            {
-             tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+             tree op0type = TREE_TYPE (top0);
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
              bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
@@ -8523,9 +8631,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                  && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
                {
-                 expand_operands (TREE_OPERAND (subsubexp0, 0),
-                                  TREE_OPERAND (subsubexp1, 0),
-                                  NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                 expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+                                  EXPAND_NORMAL);
                  op2 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
                                     VOIDmode, EXPAND_NORMAL);
                  temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
@@ -8550,7 +8657,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
          /* If the last operand is a CONST_INT, use plus_constant of
             the negated constant.  Else make the MINUS.  */
-         if (GET_CODE (op1) == CONST_INT)
+         if (CONST_INT_P (op1))
            return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
          else
            return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
@@ -8568,7 +8675,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       subtarget, &op0, &op1, modifier);
 
       /* Convert A - const to A + (-const).  */
-      if (GET_CODE (op1) == CONST_INT)
+      if (CONST_INT_P (op1))
        {
          op1 = negate_rtx (mode, op1);
          return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
@@ -8624,66 +8731,65 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       subexp0 = TREE_OPERAND (exp, 0);
       subexp1 = TREE_OPERAND (exp, 1);
+      subexp0_def = get_def_for_expr (subexp0, NOP_EXPR);
+      subexp1_def = get_def_for_expr (subexp1, NOP_EXPR);
+      top0 = top1 = NULL_TREE;
+
       /* First, check if we have a multiplication of one signed and one
         unsigned operand.  */
-      if (TREE_CODE (subexp0) == NOP_EXPR
-         && TREE_CODE (subexp1) == NOP_EXPR
+      if (subexp0_def
+         && (top0 = gimple_assign_rhs1 (subexp0_def))
+         && subexp1_def
+         && (top1 = gimple_assign_rhs1 (subexp1_def))
          && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
-         && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
-             != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+         && (TYPE_PRECISION (TREE_TYPE (top0))
+             < TYPE_PRECISION (TREE_TYPE (subexp0)))
+         && (TYPE_PRECISION (TREE_TYPE (top0))
+             == TYPE_PRECISION (TREE_TYPE (top1)))
+         && (TYPE_UNSIGNED (TREE_TYPE (top0))
+             != TYPE_UNSIGNED (TREE_TYPE (top1))))
        {
          enum machine_mode innermode
-           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+           = TYPE_MODE (TREE_TYPE (top0));
          this_optab = usmul_widen_optab;
          if (mode == GET_MODE_WIDER_MODE (innermode))
            {
              if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
                {
-                 if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
-                   expand_operands (TREE_OPERAND (subexp0, 0),
-                                    TREE_OPERAND (subexp1, 0),
-                                    NULL_RTX, &op0, &op1, 0);
+                 if (TYPE_UNSIGNED (TREE_TYPE (top0)))
+                   expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+                                    EXPAND_NORMAL);
                  else
-                   expand_operands (TREE_OPERAND (subexp0, 0),
-                                    TREE_OPERAND (subexp1, 0),
-                                    NULL_RTX, &op1, &op0, 0);
+                   expand_operands (top0, top1, NULL_RTX, &op1, &op0,
+                                    EXPAND_NORMAL);
 
                  goto binop3;
                }
            }
        }
-      /* Check for a multiplication with matching signedness.  */
-      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+      /* Check for a multiplication with matching signedness.  If
+        valid, TOP0 and TOP1 were set in the previous if
+        condition.  */
+      else if (top0
          && TREE_CODE (type) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
-         && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-              && int_fits_type_p (TREE_OPERAND (exp, 1),
-                                  TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+         && (TYPE_PRECISION (TREE_TYPE (top0))
+             < TYPE_PRECISION (TREE_TYPE (subexp0)))
+         && ((TREE_CODE (subexp1) == INTEGER_CST
+              && int_fits_type_p (subexp1, TREE_TYPE (top0))
               /* Don't use a widening multiply if a shift will do.  */
-              && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+              && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (subexp1)))
                    > HOST_BITS_PER_WIDE_INT)
-                  || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
+                  || exact_log2 (TREE_INT_CST_LOW (subexp1)) < 0))
              ||
-             (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
-              && (TYPE_PRECISION (TREE_TYPE
-                                  (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  == TYPE_PRECISION (TREE_TYPE
-                                     (TREE_OPERAND
-                                      (TREE_OPERAND (exp, 0), 0))))
+             (top1
+              && (TYPE_PRECISION (TREE_TYPE (top1))
+                  == TYPE_PRECISION (TREE_TYPE (top0))
               /* If both operands are extended, they must either both
                  be zero-extended or both be sign-extended.  */
-              && (TYPE_UNSIGNED (TREE_TYPE
-                                 (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  == TYPE_UNSIGNED (TREE_TYPE
-                                    (TREE_OPERAND
-                                     (TREE_OPERAND (exp, 0), 0)))))))
+              && (TYPE_UNSIGNED (TREE_TYPE (top1))
+                  == TYPE_UNSIGNED (TREE_TYPE (top0)))))))
        {
-         tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
+         tree op0type = TREE_TYPE (top0);
          enum machine_mode innermode = TYPE_MODE (op0type);
          bool zextend_p = TYPE_UNSIGNED (op0type);
          optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
@@ -8693,27 +8799,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            {
              if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
                {
-                 if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (exp, 1),
-                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                 if (TREE_CODE (subexp1) == INTEGER_CST)
+                   expand_operands (top0, subexp1, NULL_RTX, &op0, &op1,
+                                    EXPAND_NORMAL);
                  else
-                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+                   expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+                                    EXPAND_NORMAL);
                  goto binop3;
                }
              else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
                  rtx htem, hipart;
-                 op0 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
-                 if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+                 op0 = expand_normal (top0);
+                 if (TREE_CODE (subexp1) == INTEGER_CST)
                    op1 = convert_modes (innermode, mode,
-                                        expand_normal (TREE_OPERAND (exp, 1)),
-                                        unsignedp);
+                                        expand_normal (subexp1), unsignedp);
                  else
-                   op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
+                   op1 = expand_normal (top1);
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
                  hipart = gen_highpart (innermode, temp);
@@ -8726,8 +8829,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                }
            }
        }
-      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, 0);
+      expand_operands (subexp0, subexp1, subtarget, &op0, &op1, EXPAND_NORMAL);
       return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
     case TRUNC_DIV_EXPR:
@@ -8747,7 +8849,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         then if the divisor is constant can optimize the case
         where some terms of the dividend have coeffs divisible by it.  */
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, 0);
+                      subtarget, &op0, &op1, EXPAND_NORMAL);
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
@@ -8760,7 +8862,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      subtarget, &op0, &op1, 0);
+                      subtarget, &op0, &op1, EXPAND_NORMAL);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
     case FIXED_CONVERT_EXPR:
@@ -8837,7 +8939,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        target = gen_reg_rtx (mode);
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                      target, &op0, &op1, 0);
+                      target, &op0, &op1, EXPAND_NORMAL);
 
       /* First try to do it with a special MIN or MAX instruction.
         If that does not win, use a conditional jump to select the proper
@@ -9024,50 +9126,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       temp = do_store_flag (exp,
                            modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
                            tmode != VOIDmode ? tmode : mode);
-      if (temp != 0)
+      if (temp)
        return temp;
 
-      /* For foo != 0, load foo, and if it is nonzero load 1 instead.  */
-      if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
-         && original_target
-         && REG_P (original_target)
-         && (GET_MODE (original_target)
-             == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
-       {
-         temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
-                             VOIDmode, EXPAND_NORMAL);
-
-         /* If temp is constant, we can just compute the result.  */
-         if (GET_CODE (temp) == CONST_INT)
-           {
-             if (INTVAL (temp) != 0)
-               emit_move_insn (target, const1_rtx);
-             else
-               emit_move_insn (target, const0_rtx);
-
-             return target;
-           }
-
-         if (temp != original_target)
-           {
-             enum machine_mode mode1 = GET_MODE (temp);
-             if (mode1 == VOIDmode)
-               mode1 = tmode != VOIDmode ? tmode : mode;
-
-             temp = copy_to_mode_reg (mode1, temp);
-           }
-
-         op1 = gen_label_rtx ();
-         emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
-                                  GET_MODE (temp), unsignedp, op1);
-         emit_move_insn (temp, const1_rtx);
-         emit_label (op1);
-         return temp;
-       }
+      /* Use a compare and a jump for BLKmode comparisons, or for function
+        type comparisons is HAVE_canonicalize_funcptr_for_compare.  */
 
-      /* 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:
@@ -9274,13 +9338,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
-    case CHANGE_DYNAMIC_TYPE_EXPR:
-      /* This is ignored at the RTL level.  The tree level set
-        DECL_POINTER_ALIAS_SET of any variable to be 0, which is
-        overkill for the RTL layer but is all that we can
-        represent.  */
-      return const0_rtx;
-
     case EXC_PTR_EXPR:
       return get_exception_pointer ();
 
@@ -9345,7 +9402,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         tree oprnd0 = TREE_OPERAND (exp, 0);
         tree oprnd1 = TREE_OPERAND (exp, 1);
 
-        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
         target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
                                             target, unsignedp);
         return target;
@@ -9366,7 +9423,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case VEC_EXTRACT_ODD_EXPR:
       {
         expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
+                         NULL_RTX, &op0, &op1, EXPAND_NORMAL);
         this_optab = optab_for_tree_code (code, type, optab_default);
         temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
                              OPTAB_WIDEN);
@@ -9378,7 +9435,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case VEC_INTERLEAVE_LOW_EXPR:
       {
         expand_operands (TREE_OPERAND (exp, 0),  TREE_OPERAND (exp, 1),
-                         NULL_RTX, &op0, &op1, 0);
+                         NULL_RTX, &op0, &op1, EXPAND_NORMAL);
         this_optab = optab_for_tree_code (code, type, optab_default);
         temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
                              OPTAB_WIDEN);
@@ -9426,7 +9483,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        tree oprnd0 = TREE_OPERAND (exp, 0);
        tree oprnd1 = TREE_OPERAND (exp, 1);
 
-       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
        target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
                                            target, unsignedp);
        gcc_assert (target);
@@ -9467,7 +9524,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   /* Here to do an ordinary binary operator.  */
  binop:
   expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
-                  subtarget, &op0, &op1, 0);
+                  subtarget, &op0, &op1, EXPAND_NORMAL);
  binop2:
   this_optab = optab_for_tree_code (code, type, optab_default);
  binop3:
@@ -9489,7 +9546,7 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
   if (target && GET_MODE (target) != GET_MODE (exp))
     target = 0;
   /* For constant values, reduce using build_int_cst_type. */
-  if (GET_CODE (exp) == CONST_INT)
+  if (CONST_INT_P (exp))
     {
       HOST_WIDE_INT value = INTVAL (exp);
       tree t = build_int_cst_type (type, value);
@@ -9673,8 +9730,7 @@ string_constant (tree arg, tree *ptr_offset)
 }
 \f
 /* Generate code to calculate EXP using a store-flag instruction
-   and return an rtx for the result.  EXP is either a comparison
-   or a TRUTH_NOT_EXPR whose operand is a comparison.
+   and return an rtx for the result.  EXP is a comparison.
 
    If TARGET is nonzero, store the result there if convenient.
 
@@ -9696,19 +9752,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
   tree arg0, arg1, type;
   tree tem;
   enum machine_mode operand_mode;
-  int invert = 0;
   int unsignedp;
   rtx op0, op1;
   rtx subtarget = target;
-  rtx result, label;
-
-  /* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the
-     result at the end.  We can't simply invert the test since it would
-     have already been inverted if it were valid.  This case occurs for
-     some floating-point comparisons.  */
-
-  if (TREE_CODE (exp) == TRUTH_NOT_EXPR)
-    invert = 1, exp = TREE_OPERAND (exp, 0);
+  location_t loc = EXPR_LOCATION (exp);
 
   arg0 = TREE_OPERAND (exp, 0);
   arg1 = TREE_OPERAND (exp, 1);
@@ -9833,49 +9880,24 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
       tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
-      return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
+      return expand_expr (fold_single_bit_test (loc,
+                                               code == NE ? NE_EXPR : EQ_EXPR,
                                                arg0, arg1, type),
                          target, VOIDmode, EXPAND_NORMAL);
     }
 
-  /* Now see if we are likely to be able to do this.  Return if not.  */
-  if (! can_compare_p (code, operand_mode, ccp_store_flag))
-    return 0;
-
   if (! get_subtarget (target)
       || GET_MODE (subtarget) != operand_mode)
     subtarget = 0;
 
-  expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);
+  expand_operands (arg0, arg1, subtarget, &op0, &op1, EXPAND_NORMAL);
 
   if (target == 0)
     target = gen_reg_rtx (mode);
 
-  result = emit_store_flag (target, code, op0, op1,
-                           operand_mode, unsignedp, 1);
-
-  if (result)
-    {
-      if (invert)
-       result = expand_binop (mode, xor_optab, result, const1_rtx,
-                              result, 0, OPTAB_LIB_WIDEN);
-      return result;
-    }
-
-  /* If this failed, we have to do this with set/compare/jump/set code.  */
-  if (!REG_P (target)
-      || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
-    target = gen_reg_rtx (GET_MODE (target));
-
-  emit_move_insn (target, invert ? const0_rtx : const1_rtx);
-  label = gen_label_rtx ();
-  do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
-                          NULL_RTX, label);
-
-  emit_move_insn (target, invert ? const1_rtx : const0_rtx);
-  emit_label (label);
-
-  return target;
+  /* Try a cstore if possible.  */
+  return emit_store_flag_force (target, code, op0, op1,
+                               operand_mode, unsignedp, 1);
 }
 \f
 
@@ -9886,19 +9908,6 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode)
 # define CODE_FOR_casesi CODE_FOR_nothing
 #endif
 
-/* If the machine does not have a case insn that compares the bounds,
-   this means extra overhead for dispatch tables, which raises the
-   threshold for using them.  */
-#ifndef CASE_VALUES_THRESHOLD
-#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
-#endif /* CASE_VALUES_THRESHOLD */
-
-unsigned int
-case_values_threshold (void)
-{
-  return CASE_VALUES_THRESHOLD;
-}
-
 /* Attempt to generate a casesi instruction.  Returns 1 if successful,
    0 otherwise (i.e. if there is no casesi instruction).  */
 int