OSDN Git Service

* flags.h (g_switch_value): Change to an unsigned
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index a957dd7..9c21ac9 100644 (file)
@@ -155,7 +155,7 @@ static rtx clear_storage_via_libcall PARAMS ((rtx, rtx));
 static tree clear_storage_libcall_fn PARAMS ((int));
 static rtx compress_float_constant PARAMS ((rtx, rtx));
 static rtx get_subtarget       PARAMS ((rtx));
-static int is_zeros_p          PARAMS ((tree));
+static int is_zeros_p         PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
 static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
                                             HOST_WIDE_INT, enum machine_mode,
@@ -166,8 +166,11 @@ static rtx store_field             PARAMS ((rtx, HOST_WIDE_INT,
                                         tree, enum machine_mode, int, tree,
                                         int));
 static rtx var_rtx             PARAMS ((tree));
-static HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
-static HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree, tree));
+
+static unsigned HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree,
+                                                                   tree));
+
 static int is_aligning_offset  PARAMS ((tree, tree));
 static rtx expand_increment    PARAMS ((tree, int, int));
 static rtx do_store_flag       PARAMS ((tree, rtx, enum machine_mode, int));
@@ -175,6 +178,7 @@ static rtx do_store_flag    PARAMS ((tree, rtx, enum machine_mode, int));
 static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
 #endif
 static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
+static rtx const_vector_from_tree PARAMS ((tree));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -1459,7 +1463,7 @@ convert_modes (mode, oldmode, x, unsignedp)
    If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
    used to push FROM to the stack.
 
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum stack alignment we can assume.  */
 
 void
 move_by_pieces (to, from, len, align)
@@ -1473,6 +1477,8 @@ move_by_pieces (to, from, len, align)
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
+  align = MIN (to ? MEM_ALIGN (to) : align, MEM_ALIGN (from));
+
   data.offset = 0;
   data.from_addr = from_addr;
   if (to)
@@ -1835,16 +1841,16 @@ emit_block_move_via_movstr (x, y, size, align)
      rtx x, y, size;
      unsigned int align;
 {
-  /* Try the most limited insn first, because there's no point
-     including more than one in the machine description unless
-     the more limited one has some advantage.  */
-
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
   enum machine_mode mode;
 
   /* Since this is a move insn, we don't care about volatility.  */
   volatile_ok = 1;
 
+  /* Try the most limited insn first, because there's no point
+     including more than one in the machine description unless
+     the more limited one has some advantage.  */
+
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
@@ -1904,38 +1910,48 @@ static rtx
 emit_block_move_via_libcall (dst, src, size)
      rtx dst, src, size;
 {
+  rtx dst_addr, src_addr;
   tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
   enum machine_mode size_mode;
   rtx retval;
 
   /* DST, SRC, or SIZE may have been passed through protect_from_queue.
 
-     It is unsafe to save the value generated by protect_from_queue
-     and reuse it later.  Consider what happens if emit_queue is
-     called before the return value from protect_from_queue is used.
+     It is unsafe to save the value generated by protect_from_queue and reuse
+     it later.  Consider what happens if emit_queue is called before the
+     return value from protect_from_queue is used.
 
-     Expansion of the CALL_EXPR below will call emit_queue before
-     we are finished emitting RTL for argument setup.  So if we are
-     not careful we could get the wrong value for an argument.
+     Expansion of the CALL_EXPR below will call emit_queue before we are
+     finished emitting RTL for argument setup.  So if we are not careful we
+     could get the wrong value for an argument.
 
-     To avoid this problem we go ahead and emit code to copy X, Y &
-     SIZE into new pseudos.  We can then place those new pseudos
-     into an RTL_EXPR and use them later, even after a call to
+     To avoid this problem we go ahead and emit code to copy the addresses of
+     DST and SRC and SIZE into new pseudos.  We can then place those new
+     pseudos into an RTL_EXPR and use them later, even after a call to
      emit_queue.
 
-     Note this is not strictly needed for library calls since they
-     do not call emit_queue before loading their arguments.  However,
-     we may need to have library calls call emit_queue in the future
-     since failing to do so could cause problems for targets which
-     define SMALL_REGISTER_CLASSES and pass arguments in registers.  */
+     Note this is not strictly needed for library calls since they do not call
+     emit_queue before loading their arguments.  However, we may need to have
+     library calls call emit_queue in the future since failing to do so could
+     cause problems for targets which define SMALL_REGISTER_CLASSES and pass
+     arguments in registers.  */
+
+  dst_addr = copy_to_mode_reg (Pmode, XEXP (dst, 0));
+  src_addr = copy_to_mode_reg (Pmode, XEXP (src, 0));
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  dst_addr = convert_memory_address (ptr_mode, dst_addr);
+  src_addr = convert_memory_address (ptr_mode, src_addr);
+#endif
 
-  dst = copy_to_mode_reg (Pmode, XEXP (dst, 0));
-  src = copy_to_mode_reg (Pmode, XEXP (src, 0));
+  dst_tree = make_tree (ptr_type_node, dst_addr);
+  src_tree = make_tree (ptr_type_node, src_addr);
 
   if (TARGET_MEM_FUNCTIONS)
     size_mode = TYPE_MODE (sizetype);
   else
     size_mode = TYPE_MODE (unsigned_type_node);
+
   size = convert_to_mode (size_mode, size, 1);
   size = copy_to_mode_reg (size_mode, size);
 
@@ -1947,8 +1963,6 @@ emit_block_move_via_libcall (dst, src, size)
 
      For convenience, we generate the call to bcopy this way as well.  */
 
-  dst_tree = make_tree (ptr_type_node, dst);
-  src_tree = make_tree (ptr_type_node, src);
   if (TARGET_MEM_FUNCTIONS)
     size_tree = make_tree (sizetype, size);
   else
@@ -1975,13 +1989,17 @@ emit_block_move_via_libcall (dst, src, size)
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
-  /* If we are initializing a readonly value, show the above call
-     clobbered it.  Otherwise, a load from it may erroneously be
-     hoisted from a loop.  */
+  /* If we are initializing a readonly value, show the above call clobbered
+     it. Otherwise, a load from it may erroneously be hoisted from a loop, or
+     the delay slot scheduler might overlook conflicts and take nasty
+     decisions.  */
   if (RTX_UNCHANGING_P (dst))
-    emit_insn (gen_rtx_CLOBBER (VOIDmode, dst));
+    add_function_usage_to
+      (last_call_insn (), gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_CLOBBER (VOIDmode, dst),
+                                            NULL_RTX));
 
-  return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
+  return TARGET_MEM_FUNCTIONS ? retval : NULL_RTX;
 }
 
 /* A subroutine of emit_block_move_via_libcall.  Create the tree node
@@ -1990,15 +2008,14 @@ emit_block_move_via_libcall (dst, src, size)
 
 static GTY(()) tree block_move_fn;
 
-static tree
-emit_block_move_libcall_fn (for_call)
-      int for_call;
+void
+init_block_move_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_move_fn, args;
-
-  if (!fn)
+  if (!block_move_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
        {
          fn = get_identifier ("memcpy");
@@ -2023,14 +2040,30 @@ emit_block_move_libcall_fn (for_call)
       block_move_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_move_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_move_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+emit_block_move_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_move_fn)
+    init_block_move_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_move_fn, NULL);
+      assemble_external (block_move_fn);
     }
 
-  return fn;
+  return block_move_fn;
 }
 
 /* A subroutine of emit_block_move.  Copy the data via an explicit
@@ -2131,61 +2164,26 @@ move_block_to_reg (regno, x, nregs, mode)
 }
 
 /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
-   The number of registers to be filled is NREGS.  SIZE indicates the number
-   of bytes in the object X.  */
+   The number of registers to be filled is NREGS.  */
 
 void
-move_block_from_reg (regno, x, nregs, size)
+move_block_from_reg (regno, x, nregs)
      int regno;
      rtx x;
      int nregs;
-     int size;
 {
   int i;
-#ifdef HAVE_store_multiple
-  rtx pat;
-  rtx last;
-#endif
-  enum machine_mode mode;
 
   if (nregs == 0)
     return;
 
-  /* If SIZE is that of a mode no bigger than a word, just use that
-     mode's store operation.  */
-  if (size <= UNITS_PER_WORD
-      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
-    {
-      emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
-      return;
-    }
-
-  /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
-     to the left before storing to memory.  Note that the previous test
-     doesn't handle all cases (e.g. SIZE == 3).  */
-  if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
-    {
-      rtx tem = operand_subword (x, 0, 1, BLKmode);
-      rtx shift;
-
-      if (tem == 0)
-       abort ();
-
-      shift = expand_shift (LSHIFT_EXPR, word_mode,
-                           gen_rtx_REG (word_mode, regno),
-                           build_int_2 ((UNITS_PER_WORD - size)
-                                        * BITS_PER_UNIT, 0), NULL_RTX, 0);
-      emit_move_insn (tem, shift);
-      return;
-    }
-
   /* See if the machine can do this with a store multiple insn.  */
 #ifdef HAVE_store_multiple
   if (HAVE_store_multiple)
     {
-      last = get_last_insn ();
-      pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
-                               GEN_INT (nregs));
+      rtx last = get_last_insn ();
+      rtx pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
+                                   GEN_INT (nregs));
       if (pat)
        {
          emit_insn (pat);
@@ -2344,6 +2342,19 @@ emit_group_load (dst, orig_src, ssize)
          else
            abort ();
        }
+      /* FIXME: A SIMD parallel will eventually lead to a subreg of a
+        SIMD register, which is currently broken.  While we get GCC
+        to emit proper RTL for these cases, let's dump to memory.  */
+      else if (VECTOR_MODE_P (GET_MODE (dst))
+              && GET_CODE (src) == REG)
+       {
+         int slen = GET_MODE_SIZE (GET_MODE (src));
+         rtx mem;
+
+         mem = assign_stack_temp (GET_MODE (src), slen, 0);
+         emit_move_insn (mem, src);
+         tmps[i] = adjust_address (mem, mode, (int) bytepos);
+       }
       else if (CONSTANT_P (src)
               || (GET_CODE (src) == REG && GET_MODE (src) == mode))
        tmps[i] = src;
@@ -3085,15 +3096,14 @@ clear_storage_via_libcall (object, size)
 
 static GTY(()) tree block_clear_fn;
 
-static tree
-clear_storage_libcall_fn (for_call)
-     int for_call;
+void
+init_block_clear_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_clear_fn, args;
-
-  if (!fn)
+  if (!block_clear_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
        {
          fn = get_identifier ("memset");
@@ -3117,14 +3127,30 @@ clear_storage_libcall_fn (for_call)
       block_clear_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_clear_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_clear_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+clear_storage_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_clear_fn)
+    init_block_clear_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_clear_fn, NULL);
+      assemble_external (block_clear_fn);
     }
 
-  return fn;
+  return block_clear_fn;
 }
 \f
 /* Generate code to copy Y into X.
@@ -3825,6 +3851,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          && PUSH_ARGS
          && GET_CODE (size) == CONST_INT
          && skip == 0
+         && MEM_ALIGN (xinner) >= align
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
          /* Here we avoid the case of a structure whose weak alignment
             forces many pushes of a small amount of data,
@@ -4121,7 +4148,7 @@ expand_assignment (to, from, want_value, suggest_reg)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
-           offset_rtx = convert_memory_address (Pmode, offset_rtx);
+           offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
 #else
          if (GET_MODE (offset_rtx) != ptr_mode)
            offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
@@ -4629,7 +4656,8 @@ store_expr (exp, target, want_value)
              rtx label = 0;
 
              /* Copy that much.  */
-             copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
+             copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
+                                              TREE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
                               (want_value & 2
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
@@ -4650,8 +4678,8 @@ store_expr (exp, target, want_value)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
                  if (GET_MODE (copy_size_rtx) != Pmode)
-                   copy_size_rtx = convert_memory_address (Pmode,
-                                                           copy_size_rtx);
+                   copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
+                                                    TREE_UNSIGNED (sizetype));
 #endif
 
                  target = offset_address (target, copy_size_rtx,
@@ -4894,7 +4922,15 @@ store_constructor (exp, target, cleared, size)
                   || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
                       == size)))
        {
-         clear_storage (target, GEN_INT (size));
+         rtx xtarget = target;
+
+         if (readonly_fields_p (type))
+           {
+             xtarget = copy_rtx (xtarget);
+             RTX_UNCHANGING_P (xtarget) = 1;
+           }
+
+         clear_storage (xtarget, GEN_INT (size));
          cleared = 1;
        }
 
@@ -4956,7 +4992,7 @@ store_constructor (exp, target, cleared, size)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
              if (GET_MODE (offset_rtx) != Pmode)
-               offset_rtx = convert_memory_address (Pmode, offset_rtx);
+               offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
 #else
              if (GET_MODE (offset_rtx) != ptr_mode)
                offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
@@ -5448,8 +5484,8 @@ store_constructor (exp, target, cleared, size)
                                 TYPE_MODE (sizetype));
            }
          else
-           emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
-                              LCT_NORMAL, VOIDmode, 4, XEXP (targetx, 0),
+           emit_library_call (setbits_libfunc, LCT_NORMAL,
+                              VOIDmode, 4, XEXP (targetx, 0),
                               Pmode, bitlength_rtx, TYPE_MODE (sizetype),
                               startbit_rtx, TYPE_MODE (sizetype),
                               endbit_rtx, TYPE_MODE (sizetype));
@@ -5515,15 +5551,13 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
      that object.  Finally, load from the object into TARGET.  This is not
      very efficient in general, but should only be slightly more expensive
      than the otherwise-required unaligned accesses.  Perhaps this can be
-     cleaned up later.  */
+     cleaned up later.  It's tempting to make OBJECT readonly, but it's set
+     twice, once with emit_move_insn and once via store_field.  */
 
   if (mode == BLKmode
       && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
     {
-      rtx object
-       = assign_temp
-         (build_qualified_type (type, TYPE_QUALS (type) | TYPE_QUAL_CONST),
-          0, 1, 1);
+      rtx object = assign_temp (type, 0, 1, 1);
       rtx blk_object = adjust_address (object, BLKmode, 0);
 
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
@@ -5559,9 +5593,11 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
       || GET_CODE (target) == SUBREG
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
-      || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
-         && (MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode)
-             || bitpos % GET_MODE_ALIGNMENT (mode)))
+      || (mode != BLKmode
+         && ((((MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode))
+               || bitpos % GET_MODE_ALIGNMENT (mode))
+              && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target)))
+             || (bitpos % BITS_PER_UNIT != 0)))              
       /* If the RHS and field are a constant size and the size of the
         RHS isn't the same size as the bitfield, we must use bitfield
         operations.  */
@@ -5581,7 +5617,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
        temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
                             size_int (GET_MODE_BITSIZE (GET_MODE (temp))
                                       - bitsize),
-                            temp, 1);
+                            NULL_RTX, 1);
 
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
         MODE.  */
@@ -5821,8 +5857,20 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
          continue;
        }
+
+      /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
+        conversions that don't change the mode, and all view conversions
+        except those that need to "step up" the alignment.  */
       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
-              && TREE_CODE (exp) != VIEW_CONVERT_EXPR
+              && ! (TREE_CODE (exp) == VIEW_CONVERT_EXPR
+                    && ! ((TYPE_ALIGN (TREE_TYPE (exp))
+                           > TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))))
+                          && STRICT_ALIGNMENT
+                          && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
+                              < BIGGEST_ALIGNMENT)
+                          && (TYPE_ALIGN_OK (TREE_TYPE (exp))
+                              || TYPE_ALIGN_OK (TREE_TYPE
+                                                (TREE_OPERAND (exp, 0))))))
               && ! ((TREE_CODE (exp) == NOP_EXPR
                      || TREE_CODE (exp) == CONVERT_EXPR)
                     && (TYPE_MODE (TREE_TYPE (exp))
@@ -6092,22 +6140,31 @@ safe_from_p (x, exp, top_p)
 
     case 'x':
       if (TREE_CODE (exp) == TREE_LIST)
-       return ((TREE_VALUE (exp) == 0
-                || safe_from_p (x, TREE_VALUE (exp), 0))
-               && (TREE_CHAIN (exp) == 0
-                   || safe_from_p (x, TREE_CHAIN (exp), 0)));
+       {
+         while (1)
+           {
+             if (TREE_VALUE (exp) && !safe_from_p (x, TREE_VALUE (exp), 0))
+               return 0;
+             exp = TREE_CHAIN (exp);
+             if (!exp)
+               return 1;
+             if (TREE_CODE (exp) != TREE_LIST)
+               return safe_from_p (x, exp, 0);
+           }
+       }
       else if (TREE_CODE (exp) == ERROR_MARK)
        return 1;       /* An already-visited SAVE_EXPR? */
       else
        return 0;
 
-    case '1':
-      return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
-
     case '2':
     case '<':
-      return (safe_from_p (x, TREE_OPERAND (exp, 0), 0)
-             && safe_from_p (x, TREE_OPERAND (exp, 1), 0));
+      if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
+       return 0;
+      /* FALLTHRU */
+
+    case '1':
+      return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
 
     case 'e':
     case 'r':
@@ -6324,11 +6381,11 @@ check_max_integer_computation_mode (exp)
 /* Return the highest power of two that EXP is known to be a multiple of.
    This is used in updating alignment of MEMs in array references.  */
 
-static HOST_WIDE_INT
+static unsigned HOST_WIDE_INT
 highest_pow2_factor (exp)
      tree exp;
 {
-  HOST_WIDE_INT c0, c1;
+  unsigned HOST_WIDE_INT c0, c1;
 
   switch (TREE_CODE (exp))
     {
@@ -6394,12 +6451,12 @@ highest_pow2_factor (exp)
 /* Similar, except that it is known that the expression must be a multiple
    of the alignment of TYPE.  */
 
-static HOST_WIDE_INT
+static unsigned HOST_WIDE_INT
 highest_pow2_factor_for_type (type, exp)
      tree type;
      tree exp;
 {
-  HOST_WIDE_INT type_align, factor;
+  unsigned HOST_WIDE_INT type_align, factor;
 
   factor = highest_pow2_factor (exp);
   type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
@@ -6664,25 +6721,17 @@ expand_expr (exp, target, tmode, modifier)
     case LABEL_DECL:
       {
        tree function = decl_function_context (exp);
-       /* Handle using a label in a containing function.  */
-       if (function != current_function_decl
-           && function != inline_function_decl && function != 0)
-         {
-           struct function *p = find_function_data (function);
-           p->expr->x_forced_labels
-             = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (exp),
-                                  p->expr->x_forced_labels);
-         }
+       /* Labels in containing functions, or labels used from initializers,
+          must be forced.  */
+       if (modifier == EXPAND_INITIALIZER
+           || (function != current_function_decl
+               && function != inline_function_decl
+               && function != 0))
+         temp = force_label_rtx (exp);
        else
-         {
-           if (modifier == EXPAND_INITIALIZER)
-             forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
-                                                label_rtx (exp),
-                                                forced_labels);
-         }
+         temp = label_rtx (exp);
 
-       temp = gen_rtx_MEM (FUNCTION_MODE,
-                           gen_rtx_LABEL_REF (Pmode, label_rtx (exp)));
+       temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp));
        if (function != current_function_decl
            && function != inline_function_decl && function != 0)
          LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
@@ -6701,23 +6750,10 @@ expand_expr (exp, target, tmode, modifier)
     case VAR_DECL:
       /* If a static var's type was incomplete when the decl was written,
         but the type is complete now, lay out the decl now.  */
-      if (DECL_SIZE (exp) == 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
+      if (DECL_SIZE (exp) == 0
+         && COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (TREE_TYPE (exp))
          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
-       {
-         rtx value = DECL_RTL_IF_SET (exp);
-
-         layout_decl (exp, 0);
-
-         /* If the RTL was already set, update its mode and memory
-            attributes.  */
-         if (value != 0)
-           {
-             PUT_MODE (value, DECL_MODE (exp));
-             SET_DECL_RTL (exp, 0);
-             set_mem_attributes (value, exp, 1);
-             SET_DECL_RTL (exp, value);
-           }
-       }
+       layout_decl (exp, 0);
 
       /* ... fall through ...  */
 
@@ -6842,6 +6878,9 @@ expand_expr (exp, target, tmode, modifier)
 
       return temp;
 
+    case VECTOR_CST:
+      return const_vector_from_tree (exp);
+
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
@@ -6861,36 +6900,31 @@ expand_expr (exp, target, tmode, modifier)
 
     case COMPLEX_CST:
     case STRING_CST:
-      if (! TREE_CST_RTL (exp))
-       output_constant_def (exp, 1);
+      temp = output_constant_def (exp, 1);
 
-      /* TREE_CST_RTL probably contains a constant address.
+      /* temp contains a constant address.
         On RISC machines where a constant address isn't valid,
         make some insns to get that address into a register.  */
-      if (GET_CODE (TREE_CST_RTL (exp)) == MEM
-         && modifier != EXPAND_CONST_ADDRESS
+      if (modifier != EXPAND_CONST_ADDRESS
          && modifier != EXPAND_INITIALIZER
          && modifier != EXPAND_SUM
-         && (! memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0))
-             || (flag_force_addr
-                 && GET_CODE (XEXP (TREE_CST_RTL (exp), 0)) != REG)))
-       return replace_equiv_address (TREE_CST_RTL (exp),
-                                     copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
-      return TREE_CST_RTL (exp);
+         && (! memory_address_p (mode, XEXP (temp, 0))
+             || flag_force_addr))
+       return replace_equiv_address (temp,
+                                     copy_rtx (XEXP (temp, 0)));
+      return temp;
 
     case EXPR_WITH_FILE_LOCATION:
       {
        rtx to_return;
-       const char *saved_input_filename = input_filename;
-       int saved_lineno = lineno;
+       location_t saved_loc = input_location;
        input_filename = EXPR_WFL_FILENAME (exp);
-       lineno = EXPR_WFL_LINENO (exp);
+       input_line = EXPR_WFL_LINENO (exp);
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
-         emit_line_note (input_filename, lineno);
+         emit_line_note (input_filename, input_line);
        /* Possibly avoid switching back and forth here.  */
        to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
-       input_filename = saved_input_filename;
-       lineno = saved_lineno;
+       input_location = saved_loc;
        return to_return;
       }
 
@@ -7289,18 +7323,12 @@ expand_expr (exp, target, tmode, modifier)
              }
          }
       }
-      /* Fall through.  */
+      goto normal_inner_ref;
 
     case COMPONENT_REF:
-    case BIT_FIELD_REF:
-    case ARRAY_RANGE_REF:
       /* If the operand is a CONSTRUCTOR, we can just extract the
-        appropriate field if it is present.  Don't do this if we have
-        already written the data since we want to refer to that copy
-        and varasm.c assumes that's what we'll do.  */
-      if (code == COMPONENT_REF
-         && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
-         && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
+        appropriate field if it is present.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
        {
          tree elt;
 
@@ -7352,7 +7380,11 @@ expand_expr (exp, target, tmode, modifier)
                return op0;
              }
        }
+      goto normal_inner_ref;
 
+    case BIT_FIELD_REF:
+    case ARRAY_RANGE_REF:
+    normal_inner_ref:
       {
        enum machine_mode mode1;
        HOST_WIDE_INT bitsize, bitpos;
@@ -7435,7 +7467,7 @@ expand_expr (exp, target, tmode, modifier)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
            if (GET_MODE (offset_rtx) != Pmode)
-             offset_rtx = convert_memory_address (Pmode, offset_rtx);
+             offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
 #else
            if (GET_MODE (offset_rtx) != ptr_mode)
              offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
@@ -7500,10 +7532,10 @@ expand_expr (exp, target, tmode, modifier)
            /* If the field isn't aligned enough to fetch as a memref,
               fetch it as a bit field.  */
            || (mode1 != BLKmode
-               && SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))
-               && ((TYPE_ALIGN (TREE_TYPE (tem))
-                    < GET_MODE_ALIGNMENT (mode))
-                   || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+               && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+                    && SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0)))
+                   || (bitpos % BITS_PER_UNIT != 0)))
            /* If the type and the field are a constant size and the
               size of the type isn't the same size as the bitfield,
               we must use bitfield operations.  */
@@ -7901,12 +7933,14 @@ expand_expr (exp, target, tmode, modifier)
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
 
       /* If the input and output modes are both the same, we are done.
-        Otherwise, if neither mode is BLKmode and both are within a word, we
-        can use gen_lowpart.  If neither is true, make sure the operand is
-        in memory and convert the MEM to the new mode.  */
+        Otherwise, if neither mode is BLKmode and both are integral and within
+        a word, we can use gen_lowpart.  If neither is true, make sure the
+        operand is in memory and convert the MEM to the new mode.  */
       if (TYPE_MODE (type) == GET_MODE (op0))
        ;
       else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
+              && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+              && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
               && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
               && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
        op0 = gen_lowpart (TYPE_MODE (type), op0);
@@ -9185,7 +9219,7 @@ expand_expr (exp, target, tmode, modifier)
                                   op0);
          else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
                   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
-                  || GET_CODE (op0) == PARALLEL)
+                  || GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
            {
              /* If the operand is a SAVE_EXPR, we can deal with this by
                 forcing the SAVE_EXPR into memory.  */
@@ -10260,6 +10294,7 @@ do_tablejump (index, mode, range, table_label, default_label)
   temp = gen_reg_rtx (CASE_VECTOR_MODE);
   vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
   RTX_UNCHANGING_P (vector) = 1;
+  MEM_NOTRAP_P (vector) = 1;
   convert_move (temp, vector, 0);
 
   emit_jump_insn (gen_tablejump (temp, table_label));
@@ -10329,4 +10364,41 @@ vector_mode_valid_p (mode)
   return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
 }
 
+/* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
+static rtx
+const_vector_from_tree (exp)
+     tree exp;
+{
+  rtvec v;
+  int units, i;
+  tree link, elt;
+  enum machine_mode inner, mode;
+
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  if (is_zeros_p (exp))
+    return CONST0_RTX (mode);
+
+  units = GET_MODE_NUNITS (mode);
+  inner = GET_MODE_INNER (mode);
+
+  v = rtvec_alloc (units);
+
+  link = TREE_VECTOR_CST_ELTS (exp);
+  for (i = 0; link; link = TREE_CHAIN (link), ++i)
+    {
+      elt = TREE_VALUE (link);
+
+      if (TREE_CODE (elt) == REAL_CST)
+       RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
+                                                        inner);
+      else
+       RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
+                                              TREE_INT_CST_HIGH (elt),
+                                              inner);
+    }
+
+  return gen_rtx_raw_CONST_VECTOR (mode, v);
+}
+
 #include "gt-expr.h"