OSDN Git Service

* ifcvt.c (noce_get_alt_condition): Use reg_overlap_mentioned_p.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index b730435..810400c 100644 (file)
@@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "config.h"
 #include "system.h"
 #include "machmode.h"
+#include "real.h"
 #include "rtl.h"
 #include "tree.h"
 #include "obstack.h"
@@ -134,6 +135,7 @@ static void store_by_pieces_1       PARAMS ((struct store_by_pieces *,
 static void store_by_pieces_2  PARAMS ((rtx (*) (rtx, ...),
                                         enum machine_mode,
                                         struct store_by_pieces *));
+static rtx compress_float_constant PARAMS ((rtx, rtx));
 static rtx get_subtarget       PARAMS ((rtx));
 static int is_zeros_p          PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
@@ -147,6 +149,8 @@ static rtx store_field              PARAMS ((rtx, HOST_WIDE_INT,
                                         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 int is_aligning_offset  PARAMS ((tree, tree));
 static rtx expand_increment    PARAMS ((tree, int, int));
 static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
 static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
@@ -165,6 +169,10 @@ static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
 static char direct_load[NUM_MACHINE_MODES];
 static char direct_store[NUM_MACHINE_MODES];
 
+/* Record for each mode whether we can float-extend from memory.  */
+
+static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
+
 /* If a memory-to-memory move would take MOVE_RATIO or more simple
    move-instruction sequences, we will do a movstr or libcall instead.  */
 
@@ -184,6 +192,25 @@ static char direct_store[NUM_MACHINE_MODES];
   (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
 #endif
 
+/* If a clear memory operation would take CLEAR_RATIO or more simple
+   move-instruction sequences, we will do a clrstr or libcall instead.  */
+
+#ifndef CLEAR_RATIO
+#if defined (HAVE_clrstrqi) || defined (HAVE_clrstrhi) || defined (HAVE_clrstrsi) || defined (HAVE_clrstrdi) || defined (HAVE_clrstrti)
+#define CLEAR_RATIO 2
+#else
+/* If we are optimizing for space, cut down the default clear ratio.  */
+#define CLEAR_RATIO (optimize_size ? 3 : 15)
+#endif
+#endif
+
+/* This macro is used to determine whether clear_by_pieces should be
+   called to clear storage.  */
+#ifndef CLEAR_BY_PIECES_P
+#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
+  (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) CLEAR_RATIO)
+#endif
+
 /* This array records the insn_code of insns to perform block moves.  */
 enum insn_code movstr_optab[NUM_MACHINE_MODES];
 
@@ -206,8 +233,7 @@ init_expr_once ()
   enum machine_mode mode;
   int num_clobbers;
   rtx mem, mem1;
-
-  start_sequence ();
+  rtx reg;
 
   /* Try indexing by frame ptr and try by stack ptr.
      It is known that on the Convex the stack ptr isn't a valid index.
@@ -215,18 +241,23 @@ init_expr_once ()
   mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
   mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
 
-  insn = emit_insn (gen_rtx_SET (0, NULL_RTX, NULL_RTX));
-  pat = PATTERN (insn);
+  /* A scratch register we can modify in-place below to avoid
+     useless RTL allocations.  */
+  reg = gen_rtx_REG (VOIDmode, -1);
+
+  insn = rtx_alloc (INSN);
+  pat = gen_rtx_SET (0, NULL_RTX, NULL_RTX);
+  PATTERN (insn) = pat;
 
   for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
        mode = (enum machine_mode) ((int) mode + 1))
     {
       int regno;
-      rtx reg;
 
       direct_load[(int) mode] = direct_store[(int) mode] = 0;
       PUT_MODE (mem, mode);
       PUT_MODE (mem1, mode);
+      PUT_MODE (reg, mode);
 
       /* See if there is some register that can be used in this mode and
         directly loaded or stored from memory.  */
@@ -239,7 +270,7 @@ init_expr_once ()
            if (! HARD_REGNO_MODE_OK (regno, mode))
              continue;
 
-           reg = gen_rtx_REG (mode, regno);
+           REGNO (reg) = regno;
 
            SET_SRC (pat) = mem;
            SET_DEST (pat) = reg;
@@ -263,7 +294,27 @@ init_expr_once ()
          }
     }
 
-  end_sequence ();
+  mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000));
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      enum machine_mode srcmode;
+      for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode;
+          srcmode = GET_MODE_WIDER_MODE (srcmode))
+       {
+         enum insn_code ic;
+
+         ic = can_extend_p (mode, srcmode, 0);
+         if (ic == CODE_FOR_nothing)
+           continue;
+
+         PUT_MODE (mem, srcmode);
+
+         if ((*insn_data[ic].operand[1].predicate) (mem, srcmode))
+           float_extend_from_mem[mode][srcmode] = true;
+       }
+    }
 }
 
 /* This is run at the start of compiling a function.  */
@@ -271,7 +322,7 @@ init_expr_once ()
 void
 init_expr ()
 {
-  cfun->expr = (struct expr_status *) xmalloc (sizeof (struct expr_status));
+  cfun->expr = (struct expr_status *) ggc_alloc (sizeof (struct expr_status));
 
   pending_chain = 0;
   pending_stack_adjust = 0;
@@ -282,26 +333,6 @@ init_expr ()
   forced_labels = 0;
 }
 
-void
-mark_expr_status (p)
-     struct expr_status *p;
-{
-  if (p == NULL)
-    return;
-
-  ggc_mark_rtx (p->x_saveregs_value);
-  ggc_mark_rtx (p->x_apply_args_value);
-  ggc_mark_rtx (p->x_forced_labels);
-}
-
-void
-free_expr_status (f)
-     struct function *f;
-{
-  free (f->expr);
-  f->expr = NULL;
-}
-
 /* Small sanity check that the queue is empty at the end of a function.  */
 
 void
@@ -462,13 +493,29 @@ emit_queue ()
     {
       rtx body = QUEUED_BODY (p);
 
-      if (GET_CODE (body) == SEQUENCE)
+      switch (GET_CODE (body))
        {
-         QUEUED_INSN (p) = XVECEXP (QUEUED_BODY (p), 0, 0);
-         emit_insn (QUEUED_BODY (p));
+       case INSN:
+       case JUMP_INSN:
+       case CALL_INSN:
+       case CODE_LABEL:
+       case BARRIER:
+       case NOTE:
+         QUEUED_INSN (p) = body;
+         emit_insn (body);
+         break;
+
+#ifdef ENABLE_CHECKING
+       case SEQUENCE:
+         abort ();
+         break;
+#endif
+
+       default:
+         QUEUED_INSN (p) = emit_insn (body);
+         break;
        }
-      else
-       QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
+
       pending_chain = QUEUED_NEXT (p);
     }
 }
@@ -1352,7 +1399,7 @@ convert_modes (mode, oldmode, x, unsignedp)
              && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
            val |= (HOST_WIDE_INT) (-1) << width;
 
-         return GEN_INT (trunc_int_for_mode (val, mode));
+         return gen_int_mode (val, mode);
        }
 
       return gen_lowpart (mode, x);
@@ -1374,6 +1421,13 @@ convert_modes (mode, oldmode, x, unsignedp)
 #define MOVE_MAX_PIECES   MOVE_MAX
 #endif
 
+/* STORE_MAX_PIECES is the number of bytes at a time that we can
+   store efficiently.  Due to internal GCC limitations, this is
+   MOVE_MAX_PIECES limited by the number of bytes GCC can represent
+   for an immediate constant.  */
+
+#define STORE_MAX_PIECES  MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
+
 /* Generate several move instructions to copy LEN bytes from block FROM to
    block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
    and TO through protect_from_queue before calling.
@@ -1616,6 +1670,7 @@ move_by_pieces_1 (genfun, mode, data)
    Return the address of the new block, if memcpy is called and returns it,
    0 otherwise.  */
 
+static GTY(()) tree block_move_fn;
 rtx
 emit_block_move (x, y, size)
      rtx x, y;
@@ -1623,7 +1678,6 @@ emit_block_move (x, y, size)
 {
   rtx retval = 0;
 #ifdef TARGET_MEM_FUNCTIONS
-  static tree fn;
   tree call_expr, arg_list;
 #endif
   unsigned int align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
@@ -1747,23 +1801,22 @@ emit_block_move (x, y, size)
 
         So instead of using a libcall sequence we build up a suitable
         CALL_EXPR and expand the call in the normal fashion.  */
-      if (fn == NULL_TREE)
+      if (block_move_fn == NULL_TREE)
        {
          tree fntype;
 
          /* This was copied from except.c, I don't know if all this is
             necessary in this context or not.  */
-         fn = get_identifier ("memcpy");
+         block_move_fn = get_identifier ("memcpy");
          fntype = build_pointer_type (void_type_node);
          fntype = build_function_type (fntype, NULL_TREE);
-         fn = build_decl (FUNCTION_DECL, fn, fntype);
-         ggc_add_tree_root (&fn, 1);
-         DECL_EXTERNAL (fn) = 1;
-         TREE_PUBLIC (fn) = 1;
-         DECL_ARTIFICIAL (fn) = 1;
-         TREE_NOTHROW (fn) = 1;
-         make_decl_rtl (fn, NULL);
-         assemble_external (fn);
+         block_move_fn = build_decl (FUNCTION_DECL, block_move_fn, fntype);
+         DECL_EXTERNAL (block_move_fn) = 1;
+         TREE_PUBLIC (block_move_fn) = 1;
+         DECL_ARTIFICIAL (block_move_fn) = 1;
+         TREE_NOTHROW (block_move_fn) = 1;
+         make_decl_rtl (block_move_fn, NULL);
+         assemble_external (block_move_fn);
        }
 
       /* We need to make an argument list for the function call.
@@ -1781,8 +1834,10 @@ emit_block_move (x, y, size)
       TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
 
       /* Now we have to build up the CALL_EXPR itself.  */
-      call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+      call_expr = build1 (ADDR_EXPR, 
+                         build_pointer_type (TREE_TYPE (block_move_fn)), 
+                         block_move_fn);
+      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (block_move_fn)),
                         call_expr, arg_list, NULL_TREE);
       TREE_SIDE_EFFECTS (call_expr) = 1;
 
@@ -2004,12 +2059,17 @@ emit_group_load (dst, orig_src, ssize)
        }
       else if (GET_CODE (src) == CONCAT)
        {
-         if (bytepos == 0
-             && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
-           tmps[i] = XEXP (src, 0);
-         else if (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-                  && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
-           tmps[i] = XEXP (src, 1);
+         if ((bytepos == 0
+              && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
+             || (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+                 && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1)))))
+           {
+             tmps[i] = XEXP (src, bytepos != 0);
+             if (! CONSTANT_P (tmps[i])
+                 && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
+               tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
+                                            0, 1, NULL_RTX, mode, mode, ssize);
+           }
          else if (bytepos == 0)
            {
              rtx mem = assign_stack_temp (GET_MODE (src),
@@ -2095,7 +2155,7 @@ emit_group_store (orig_dst, src, ssize)
       emit_group_load (dst, temp, ssize);
       return;
     }
-  else if (GET_CODE (dst) != MEM)
+  else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
     {
       dst = gen_reg_rtx (GET_MODE (orig_dst));
       /* Make life a bit easier for combine.  */
@@ -2108,6 +2168,7 @@ emit_group_store (orig_dst, src, ssize)
       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
       unsigned int bytelen = GET_MODE_SIZE (mode);
+      rtx dest = dst;
 
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
@@ -2121,14 +2182,27 @@ emit_group_store (orig_dst, src, ssize)
          bytelen = ssize - bytepos;
        }
 
+      if (GET_CODE (dst) == CONCAT)
+       {
+         if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           dest = XEXP (dst, 0);
+         else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+           {
+             bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
+             dest = XEXP (dst, 1);
+           }
+         else
+           abort ();
+       }
+
       /* Optimize the access just a bit.  */
-      if (GET_CODE (dst) == MEM
-         && MEM_ALIGN (dst) >= GET_MODE_ALIGNMENT (mode)
+      if (GET_CODE (dest) == MEM
+         && MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode)
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
-       emit_move_insn (adjust_address (dst, mode, bytepos), tmps[i]);
+       emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
       else
-       store_bit_field (dst, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
+       store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
                         mode, tmps[i], ssize);
     }
 
@@ -2259,7 +2333,7 @@ use_regs (call_fusage, regno, nregs)
     abort ();
 
   for (i = 0; i < nregs; i++)
-    use_reg (call_fusage, gen_rtx_REG (reg_raw_mode[regno + i], regno + i));
+    use_reg (call_fusage, regno_reg_rtx[regno + i]);
 }
 
 /* Add USE expressions to *CALL_FUSAGE for each REG contained in the
@@ -2286,6 +2360,12 @@ use_group_regs (call_fusage, regs)
 }
 \f
 
+/* Determine whether the LEN bytes generated by CONSTFUN can be
+   stored to memory using several move instructions.  CONSTFUNDATA is
+   a pointer which will be passed as argument in every CONSTFUN call.
+   ALIGN is maximum alignment we can assume.  Return nonzero if a
+   call to store_by_pieces should succeed.  */
+
 int
 can_store_by_pieces (len, constfun, constfundata, align)
      unsigned HOST_WIDE_INT len;
@@ -2316,7 +2396,7 @@ can_store_by_pieces (len, constfun, constfundata, align)
     {
       l = len;
       mode = VOIDmode;
-      max_size = MOVE_MAX_PIECES + 1;
+      max_size = STORE_MAX_PIECES + 1;
       while (max_size > 1)
        {
          for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -2427,7 +2507,7 @@ store_by_pieces_1 (data, align)
      unsigned int align;
 {
   rtx to_addr = XEXP (data->to, 0);
-  unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
+  unsigned HOST_WIDE_INT max_size = STORE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
@@ -2547,13 +2627,13 @@ store_by_pieces_2 (genfun, mode, data)
 /* Write zeros through the storage of OBJECT.  If OBJECT has BLKmode, SIZE is
    its length in bytes.  */
 
+static GTY(()) tree block_clear_fn;
 rtx
 clear_storage (object, size)
      rtx object;
      rtx size;
 {
 #ifdef TARGET_MEM_FUNCTIONS
-  static tree fn;
   tree call_expr, arg_list;
 #endif
   rtx retval = 0;
@@ -2572,7 +2652,7 @@ clear_storage (object, size)
       size = protect_from_queue (size, 0);
 
       if (GET_CODE (size) == CONST_INT
-         && MOVE_BY_PIECES_P (INTVAL (size), align))
+         && CLEAR_BY_PIECES_P (INTVAL (size), align))
        clear_by_pieces (object, INTVAL (size), align);
       else
        {
@@ -2666,23 +2746,23 @@ clear_storage (object, size)
 
             So instead of using a libcall sequence we build up a suitable
             CALL_EXPR and expand the call in the normal fashion.  */
-         if (fn == NULL_TREE)
+         if (block_clear_fn == NULL_TREE)
            {
              tree fntype;
 
              /* This was copied from except.c, I don't know if all this is
                 necessary in this context or not.  */
-             fn = get_identifier ("memset");
+             block_clear_fn = get_identifier ("memset");
              fntype = build_pointer_type (void_type_node);
              fntype = build_function_type (fntype, NULL_TREE);
-             fn = build_decl (FUNCTION_DECL, fn, fntype);
-             ggc_add_tree_root (&fn, 1);
-             DECL_EXTERNAL (fn) = 1;
-             TREE_PUBLIC (fn) = 1;
-             DECL_ARTIFICIAL (fn) = 1;
-             TREE_NOTHROW (fn) = 1;
-             make_decl_rtl (fn, NULL);
-             assemble_external (fn);
+             block_clear_fn = build_decl (FUNCTION_DECL, block_clear_fn,
+                                          fntype);
+             DECL_EXTERNAL (block_clear_fn) = 1;
+             TREE_PUBLIC (block_clear_fn) = 1;
+             DECL_ARTIFICIAL (block_clear_fn) = 1;
+             TREE_NOTHROW (block_clear_fn) = 1;
+             make_decl_rtl (block_clear_fn, NULL);
+             assemble_external (block_clear_fn);
            }
 
          /* We need to make an argument list for the function call.
@@ -2703,8 +2783,9 @@ clear_storage (object, size)
 
          /* Now we have to build up the CALL_EXPR itself.  */
          call_expr = build1 (ADDR_EXPR,
-                             build_pointer_type (TREE_TYPE (fn)), fn);
-         call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                             build_pointer_type (TREE_TYPE (block_clear_fn)),
+                             block_clear_fn);
+         call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (block_clear_fn)),
                             call_expr, arg_list, NULL_TREE);
          TREE_SIDE_EFFECTS (call_expr) = 1;
 
@@ -2750,10 +2831,18 @@ emit_move_insn (x, y)
   /* Never force constant_p_rtx to memory.  */
   if (GET_CODE (y) == CONSTANT_P_RTX)
     ;
-  else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
+  else if (CONSTANT_P (y))
     {
-      y_cst = y;
-      y = force_const_mem (mode, y);
+      if (optimize
+         && FLOAT_MODE_P (GET_MODE (x))
+         && (last_insn = compress_float_constant (x, y)))
+       return last_insn;
+
+      if (!LEGITIMATE_CONSTANT_P (y))
+       {
+         y_cst = y;
+         y = force_const_mem (mode, y);
+       }
     }
 
   /* If X or Y are memory references, verify that their addresses are valid
@@ -2969,10 +3058,10 @@ emit_move_insn_1 (x, y)
       return get_last_insn ();
     }
 
-  /* This will handle any multi-word mode that lacks a move_insn pattern.
-     However, you will get better code if you define such patterns,
+  /* This will handle any multi-word or full-word mode that lacks a move_insn
+     pattern.  However, you will get better code if you define such patterns,
      even if they must turn into multiple assembler instructions.  */
-  else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+  else if (GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
     {
       rtx last_insn = 0;
       rtx seq, inner;
@@ -2987,7 +3076,7 @@ emit_move_insn_1 (x, y)
        {
          rtx temp;
          enum rtx_code code;
-         
+
          /* Do not use anti_adjust_stack, since we don't want to update
             stack_pointer_delta.  */
          temp = expand_binop (Pmode,
@@ -3002,18 +3091,18 @@ emit_move_insn_1 (x, y)
                                  (GET_MODE_SIZE (GET_MODE (x)))),
                               stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
 
-          if (temp != stack_pointer_rtx)
-            emit_move_insn (stack_pointer_rtx, temp);
+         if (temp != stack_pointer_rtx)
+           emit_move_insn (stack_pointer_rtx, temp);
 
          code = GET_CODE (XEXP (x, 0));
 
          /* Just hope that small offsets off SP are OK.  */
          if (code == POST_INC)
-           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 
+           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (-((HOST_WIDE_INT)
                                           GET_MODE_SIZE (GET_MODE (x)))));
          else if (code == POST_DEC)
-           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 
+           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
          else
            temp = stack_pointer_rtx;
@@ -3060,7 +3149,7 @@ emit_move_insn_1 (x, y)
          last_insn = emit_move_insn (xpart, ypart);
        }
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       /* Show the output dies here.  This is necessary for SUBREGs
@@ -3079,6 +3168,64 @@ emit_move_insn_1 (x, y)
   else
     abort ();
 }
+
+/* If Y is representable exactly in a narrower mode, and the target can
+   perform the extension directly from constant or memory, then emit the
+   move as an extension.  */
+
+static rtx
+compress_float_constant (x, y)
+     rtx x, y;
+{
+  enum machine_mode dstmode = GET_MODE (x);
+  enum machine_mode orig_srcmode = GET_MODE (y);
+  enum machine_mode srcmode;
+  REAL_VALUE_TYPE r;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (r, y);
+
+  for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
+       srcmode != orig_srcmode;
+       srcmode = GET_MODE_WIDER_MODE (srcmode))
+    {
+      enum insn_code ic;
+      rtx trunc_y, last_insn;
+
+      /* Skip if the target can't extend this way.  */
+      ic = can_extend_p (dstmode, srcmode, 0);
+      if (ic == CODE_FOR_nothing)
+       continue;
+
+      /* Skip if the narrowed value isn't exact.  */
+      if (! exact_real_truncate (srcmode, &r))
+       continue;
+
+      trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode);
+
+      if (LEGITIMATE_CONSTANT_P (trunc_y))
+       {
+         /* Skip if the target needs extra instructions to perform
+            the extension.  */
+         if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
+           continue;
+       }
+      else if (float_extend_from_mem[dstmode][srcmode])
+       trunc_y = validize_mem (force_const_mem (srcmode, trunc_y));
+      else
+       continue;
+
+      emit_unop_insn (ic, x, trunc_y, UNKNOWN);
+      last_insn = get_last_insn ();
+
+      if (GET_CODE (x) == REG)
+       REG_NOTES (last_insn)
+         = gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn));
+
+      return last_insn;
+    }
+
+  return NULL_RTX;
+}
 \f
 /* Pushing data onto the stack.  */
 
@@ -3232,7 +3379,7 @@ emit_single_push_insn (mode, x, type)
 void
 emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                args_addr, args_so_far, reg_parm_stack_space,
-                alignment_pad)
+               alignment_pad)
      rtx x;
      enum machine_mode mode;
      tree type;
@@ -3259,7 +3406,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
      Default is below for small data on big-endian machines; else above.  */
   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
 
-  /* Invert direction if stack is post-decrement. 
+  /* Invert direction if stack is post-decrement.
      FIXME: why?  */
   if (STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
@@ -3664,12 +3811,12 @@ expand_assignment (to, from, want_value, suggest_reg)
          if (GET_CODE (to_rtx) != MEM)
            abort ();
 
-         if (GET_MODE (offset_rtx) != ptr_mode)
-           offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
            offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+         if (GET_MODE (offset_rtx) != ptr_mode)
+           offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
          /* A constant address in TO_RTX can have VOIDmode, we must not try
@@ -3687,7 +3834,8 @@ expand_assignment (to, from, want_value, suggest_reg)
            }
 
          to_rtx = offset_address (to_rtx, offset_rtx,
-                                  highest_pow2_factor (offset));
+                                  highest_pow2_factor_for_type (TREE_TYPE (to),
+                                                                offset));
        }
 
       if (GET_CODE (to_rtx) == MEM)
@@ -3698,17 +3846,7 @@ expand_assignment (to, from, want_value, suggest_reg)
             DECL_RTX of the parent struct.  Don't munge it.  */
          to_rtx = shallow_copy_rtx (to_rtx);
 
-         set_mem_attributes (to_rtx, to, 0);
-
-         /* If we changed MEM_EXPR, that means we're now referencing
-            the COMPONENT_REF, which means that MEM_OFFSET must be
-            relative to that field.  But we've not yet reflected BITPOS
-            in TO_RTX.  This will be done in store_field.  Adjust for
-            that by biasing MEM_OFFSET by -bitpos.  */
-         if (MEM_EXPR (to_rtx) != old_expr && MEM_OFFSET (to_rtx)
-             && (bitpos / BITS_PER_UNIT) != 0)
-           set_mem_offset (to_rtx, GEN_INT (INTVAL (MEM_OFFSET (to_rtx))
-                                            - (bitpos / BITS_PER_UNIT)));
+         set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
        }
 
       /* Deal with volatile and readonly fields.  The former is only done
@@ -3989,6 +4127,8 @@ store_expr (exp, target, want_value)
        and then convert to the wider mode.  Our value is the computed
        expression.  */
     {
+      rtx inner_target = 0;
+
       /* If we don't want a value, we can do the conversion inside EXP,
         which will often result in some optimizations.  Do the conversion
         in two steps: first change the signedness, if needed, then
@@ -4000,18 +4140,19 @@ store_expr (exp, target, want_value)
        {
          if (TREE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
-           exp
-             = convert
-               (signed_or_unsigned_type (SUBREG_PROMOTED_UNSIGNED_P (target),
-                                         TREE_TYPE (exp)),
-                exp);
-
-         exp = convert (type_for_mode (GET_MODE (SUBREG_REG (target)),
-                                       SUBREG_PROMOTED_UNSIGNED_P (target)),
+           exp = convert
+             ((*lang_hooks.types.signed_or_unsigned_type)
+              (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
+
+         exp = convert ((*lang_hooks.types.type_for_mode)
+                        (GET_MODE (SUBREG_REG (target)),
+                         SUBREG_PROMOTED_UNSIGNED_P (target)),
                         exp);
+
+         inner_target = SUBREG_REG (target);
        }
 
-      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+      temp = expand_expr (exp, inner_target, VOIDmode, 0);
 
       /* If TEMP is a volatile MEM and we want a result value, make
         the access now so it gets done only once.  Likewise if
@@ -4045,8 +4186,8 @@ store_expr (exp, target, want_value)
            {
              temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
              SUBREG_PROMOTED_VAR_P (temp) = 1;
-             SUBREG_PROMOTED_UNSIGNED_P (temp)
-               = SUBREG_PROMOTED_UNSIGNED_P (target);
+             SUBREG_PROMOTED_UNSIGNED_SET (temp,
+               SUBREG_PROMOTED_UNSIGNED_P (target));
            }
          else
            temp = convert_modes (GET_MODE (target),
@@ -4102,7 +4243,12 @@ store_expr (exp, target, want_value)
        || (temp != target && (side_effects_p (temp)
                              || side_effects_p (target))))
       && TREE_CODE (exp) != ERROR_MARK
-      && ! dont_store_target)
+      && ! dont_store_target
+        /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
+           but TARGET is not valid memory reference, TEMP will differ
+           from TARGET although it is really the same location.  */
+      && (TREE_CODE_CLASS (TREE_CODE (exp)) != 'd'
+         || target != DECL_RTL_IF_SET (exp)))
     {
       target = protect_from_queue (target, 1);
       if (GET_MODE (temp) != GET_MODE (target)
@@ -4157,7 +4303,7 @@ store_expr (exp, target, want_value)
                }
              else
                {
-                 size = expand_binop (ptr_mode, sub_optab, size,
+                 size = expand_binop (TYPE_MODE (sizetype), sub_optab, size,
                                       copy_size_rtx, NULL_RTX, 0,
                                       OPTAB_LIB_WIDEN);
 
@@ -4466,12 +4612,12 @@ store_constructor (exp, target, cleared, size)
              if (GET_CODE (to_rtx) != MEM)
                abort ();
 
-             if (GET_MODE (offset_rtx) != ptr_mode)
-               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
 #ifdef POINTERS_EXTEND_UNSIGNED
              if (GET_MODE (offset_rtx) != Pmode)
                offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+             if (GET_MODE (offset_rtx) != ptr_mode)
+               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
              to_rtx = offset_address (to_rtx, offset_rtx,
@@ -4503,7 +4649,8 @@ store_constructor (exp, target, cleared, size)
 
              if (TYPE_PRECISION (type) < BITS_PER_WORD)
                {
-                 type = type_for_size (BITS_PER_WORD, TREE_UNSIGNED (type));
+                 type = (*lang_hooks.types.type_for_size)
+                   (BITS_PER_WORD, TREE_UNSIGNED (type));
                  value = convert (type, value);
                }
 
@@ -4932,7 +5079,8 @@ store_constructor (exp, target, cleared, size)
            {
              targetx
                = assign_temp
-                 ((build_qualified_type (type_for_mode (GET_MODE (target), 0),
+                 ((build_qualified_type ((*lang_hooks.types.type_for_mode)
+                                         (GET_MODE (target), 0),
                                          TYPE_QUAL_CONST)),
                   0, 1, 1);
              emit_move_insn (targetx, target);
@@ -5141,8 +5289,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
 
              if (unsignedp)
                return expand_and (tmode, temp,
-                                  GEN_INT (trunc_int_for_mode (width_mask,
-                                                               tmode)),
+                                  gen_int_mode (width_mask, tmode),
                                   NULL_RTX);
 
              count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
@@ -5403,16 +5550,13 @@ rtx
 force_operand (value, target)
      rtx value, target;
 {
-  optab binoptab = 0;
-  /* Use a temporary to force order of execution of calls to
-     `force_operand'.  */
-  rtx tmp;
-  rtx op2;
+  rtx op1, op2;
   /* Use subtarget as the target for operand 0 of a binary operation.  */
   rtx subtarget = get_subtarget (target);
+  enum rtx_code code = GET_CODE (value);
 
   /* Check for a PIC address load.  */
-  if ((GET_CODE (value) == PLUS || GET_CODE (value) == MINUS)
+  if ((code == PLUS || code == MINUS)
       && XEXP (value, 0) == pic_offset_table_rtx
       && (GET_CODE (XEXP (value, 1)) == SYMBOL_REF
          || GET_CODE (XEXP (value, 1)) == LABEL_REF
@@ -5424,60 +5568,88 @@ force_operand (value, target)
       return subtarget;
     }
 
-  if (GET_CODE (value) == PLUS)
-    binoptab = add_optab;
-  else if (GET_CODE (value) == MINUS)
-    binoptab = sub_optab;
-  else if (GET_CODE (value) == MULT)
+  if (code == ZERO_EXTEND || code == SIGN_EXTEND)
     {
-      op2 = XEXP (value, 1);
-      if (!CONSTANT_P (op2)
-         && !(GET_CODE (op2) == REG && op2 != subtarget))
-       subtarget = 0;
-      tmp = force_operand (XEXP (value, 0), subtarget);
-      return expand_mult (GET_MODE (value), tmp,
-                         force_operand (op2, NULL_RTX),
-                         target, 1);
+      if (!target)
+       target = gen_reg_rtx (GET_MODE (value));
+      convert_move (target, force_operand (XEXP (value, 0), NULL),
+                   code == ZERO_EXTEND);
+      return target;
     }
 
-  if (binoptab)
+  if (GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
     {
       op2 = XEXP (value, 1);
-      if (!CONSTANT_P (op2)
-         && !(GET_CODE (op2) == REG && op2 != subtarget))
+      if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
        subtarget = 0;
-      if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT)
+      if (code == MINUS && GET_CODE (op2) == CONST_INT)
        {
-         binoptab = add_optab;
+         code = PLUS;
          op2 = negate_rtx (GET_MODE (value), op2);
        }
 
       /* Check for an addition with OP2 a constant integer and our first
-        operand a PLUS of a virtual register and something else.  In that
-        case, we want to emit the sum of the virtual register and the
-        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 (binoptab == add_optab && GET_CODE (op2) == CONST_INT
+         operand a PLUS of a virtual register and something else.  In that
+         case, we want to emit the sum of the virtual register and the
+         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
          && GET_CODE (XEXP (value, 0)) == PLUS
          && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
          && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
        {
-         rtx temp = expand_binop (GET_MODE (value), binoptab,
-                                  XEXP (XEXP (value, 0), 0), op2,
-                                  subtarget, 0, OPTAB_LIB_WIDEN);
-         return expand_binop (GET_MODE (value), binoptab, temp,
-                              force_operand (XEXP (XEXP (value, 0), 1), 0),
-                              target, 0, OPTAB_LIB_WIDEN);
+         rtx temp = expand_simple_binop (GET_MODE (value), code,
+                                         XEXP (XEXP (value, 0), 0), op2,
+                                         subtarget, 0, OPTAB_LIB_WIDEN);
+         return expand_simple_binop (GET_MODE (value), code, temp,
+                                     force_operand (XEXP (XEXP (value,
+                                                                0), 1), 0),
+                                     target, 0, OPTAB_LIB_WIDEN);
+       }
+
+      op1 = force_operand (XEXP (value, 0), subtarget);
+      op2 = force_operand (op2, NULL_RTX);
+      switch (code)
+       {
+       case MULT:
+         return expand_mult (GET_MODE (value), op1, op2, target, 1);
+       case DIV:
+         if (!INTEGRAL_MODE_P (GET_MODE (value)))
+           return expand_simple_binop (GET_MODE (value), code, op1, op2,
+                                       target, 1, OPTAB_LIB_WIDEN);
+         else
+           return expand_divmod (0,
+                                 FLOAT_MODE_P (GET_MODE (value))
+                                 ? RDIV_EXPR : TRUNC_DIV_EXPR,
+                                 GET_MODE (value), op1, op2, target, 0);
+         break;
+       case MOD:
+         return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
+                               target, 0);
+         break;
+       case UDIV:
+         return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
+                               target, 1);
+         break;
+       case UMOD:
+         return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
+                               target, 1);
+         break;
+       case ASHIFTRT:
+         return expand_simple_binop (GET_MODE (value), code, op1, op2,
+                                     target, 0, OPTAB_LIB_WIDEN);
+         break;
+       default:
+         return expand_simple_binop (GET_MODE (value), code, op1, op2,
+                                     target, 1, OPTAB_LIB_WIDEN);
        }
-
-      tmp = force_operand (XEXP (value, 0), subtarget);
-      return expand_binop (GET_MODE (value), binoptab, tmp,
-                          force_operand (op2, NULL_RTX),
-                          target, 0, OPTAB_LIB_WIDEN);
-      /* We give UNSIGNEDP = 0 to expand_binop
-        because the only operations we are expanding here are signed ones.  */
+    }
+  if (GET_RTX_CLASS (code) == '1')
+    {
+      op1 = force_operand (XEXP (value, 0), NULL_RTX);
+      return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
     }
 
 #ifdef INSN_SCHEDULING
@@ -5574,7 +5746,7 @@ safe_from_p (x, exp, top_p)
   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
     {
     case 'd':
-      exp_rtl = DECL_RTL_SET_P (exp) ? DECL_RTL (exp) : NULL_RTX;
+      exp_rtl = DECL_RTL_IF_SET (exp);
       break;
 
     case 'c':
@@ -5823,20 +5995,21 @@ highest_pow2_factor (exp)
   switch (TREE_CODE (exp))
     {
     case INTEGER_CST:
-      /* If the integer is expressable in a HOST_WIDE_INT, we can find the
-        lowest bit that's a one.  If the result is zero, return
-        BIGGEST_ALIGNMENT.  We need to handle this case since we can find it
-        in a COND_EXPR, a MIN_EXPR, or a MAX_EXPR.  If the constant overlows,
-        we have an erroneous program, so return BIGGEST_ALIGNMENT to avoid any
+      /* We can find the lowest bit that's a one.  If the low
+        HOST_BITS_PER_WIDE_INT bits are zero, return BIGGEST_ALIGNMENT.
+        We need to handle this case since we can find it in a COND_EXPR,
+        a MIN_EXPR, or a MAX_EXPR.  If the constant overlows, we have an
+        erroneous program, so return BIGGEST_ALIGNMENT to avoid any
         later ICE.  */
-      if (TREE_CONSTANT_OVERFLOW (exp)
-         || integer_zerop (exp))
+      if (TREE_CONSTANT_OVERFLOW (exp))
        return BIGGEST_ALIGNMENT;
-      else if (host_integerp (exp, 0))
+      else
        {
-         c0 = tree_low_cst (exp, 0);
-         c0 = c0 < 0 ? - c0 : c0;
-         return c0 & -c0;
+         /* Note: tree_low_cst is intentionally not used here,
+            we don't care about the upper bits.  */
+         c0 = TREE_INT_CST_LOW (exp);
+         c0 &= -c0;
+         return c0 ? c0 : BIGGEST_ALIGNMENT;
        }
       break;
 
@@ -5879,6 +6052,21 @@ highest_pow2_factor (exp)
 
   return 1;
 }
+
+/* Similar, except that it is known that the expression must be a multiple
+   of the alignment of TYPE.  */
+
+static HOST_WIDE_INT
+highest_pow2_factor_for_type (type, exp)
+     tree type;
+     tree exp;
+{
+  HOST_WIDE_INT type_align, factor;
+
+  factor = highest_pow2_factor (exp);
+  type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
+  return MAX (factor, type_align);
+}
 \f
 /* Return an object on the placeholder list that matches EXP, a
    PLACEHOLDER_EXPR.  An object "matches" if it is of the type of the
@@ -6223,7 +6411,7 @@ expand_expr (exp, target, tmode, modifier)
          DECL_NONLOCAL (exp) = 1;
          if (DECL_NO_STATIC_CHAIN (current_function_decl))
            abort ();
-         mark_addressable (exp);
+         (*lang_hooks.mark_addressable) (exp);
          if (GET_CODE (DECL_RTL (exp)) != MEM)
            abort ();
          addr = XEXP (DECL_RTL (exp), 0);
@@ -6280,21 +6468,33 @@ expand_expr (exp, target, tmode, modifier)
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
          if (GET_MODE (DECL_RTL (exp))
-             != promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
+             != promote_mode (type, DECL_MODE (exp), &unsignedp,
+                              (TREE_CODE (exp) == RESULT_DECL ? 1 : 0)))
            abort ();
 
          temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
          SUBREG_PROMOTED_VAR_P (temp) = 1;
-         SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
+         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
          return temp;
        }
 
       return DECL_RTL (exp);
 
     case INTEGER_CST:
-      return immed_double_const (TREE_INT_CST_LOW (exp),
+      temp = immed_double_const (TREE_INT_CST_LOW (exp),
                                 TREE_INT_CST_HIGH (exp), mode);
 
+      /* ??? If overflow is set, fold will have done an incomplete job,
+        which can result in (plus xx (const_int 0)), which can get
+        simplified by validate_replace_rtx during virtual register
+        instantiation, which can result in unrecognizable insns.
+        Avoid this by forcing all overflows into registers.  */
+      if (TREE_CONSTANT_OVERFLOW (exp)
+         && modifier != EXPAND_INITIALIZER)
+       temp = force_reg (mode, temp);
+
+      return temp;
+
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
 
@@ -6309,7 +6509,8 @@ expand_expr (exp, target, tmode, modifier)
         many insns, so we'd end up copying it to a register in any case.
 
         Now, we do the copying in expand_binop, if appropriate.  */
-      return immed_real_const (exp);
+      return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
+                                          TYPE_MODE (TREE_TYPE (exp)));
 
     case COMPLEX_CST:
     case STRING_CST:
@@ -6405,7 +6606,7 @@ expand_expr (exp, target, tmode, modifier)
            {
              temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
              SUBREG_PROMOTED_VAR_P (temp) = 1;
-             SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
+             SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
            }
 
          if (temp == const0_rtx)
@@ -6427,7 +6628,7 @@ expand_expr (exp, target, tmode, modifier)
          promote_mode (type, mode, &unsignedp, 0);
          temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
          SUBREG_PROMOTED_VAR_P (temp) = 1;
-         SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
+         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
          return temp;
        }
 
@@ -6437,7 +6638,8 @@ expand_expr (exp, target, tmode, modifier)
       {
        rtx temp;
        temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-       TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
+       TREE_OPERAND (exp, 0)
+         = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
        return temp;
       }
 
@@ -6516,7 +6718,7 @@ expand_expr (exp, target, tmode, modifier)
        /* Mark the corresponding BLOCK for output in its proper place.  */
        if (TREE_OPERAND (exp, 2) != 0
            && ! TREE_USED (TREE_OPERAND (exp, 2)))
-         insert_block (TREE_OPERAND (exp, 2));
+         (*lang_hooks.decls.insert_block) (TREE_OPERAND (exp, 2));
 
        /* If VARS have not yet been expanded, expand them now.  */
        while (vars)
@@ -6542,7 +6744,7 @@ expand_expr (exp, target, tmode, modifier)
        {
          if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
            abort ();
-         emit_insns (RTL_EXPR_SEQUENCE (exp));
+         emit_insn (RTL_EXPR_SEQUENCE (exp));
          RTL_EXPR_SEQUENCE (exp) = const0_rtx;
        }
       preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
@@ -6568,7 +6770,13 @@ expand_expr (exp, target, tmode, modifier)
         fold.  Likewise, if we have a target we can use, it is best to
         store directly into the target unless the type is large enough
         that memcpy will be used.  If we are making an initializer and
-        all operands are constant, put it in memory as well.  */
+        all operands are constant, put it in memory as well.
+
+       FIXME: Avoid trying to fill vector constructors piece-meal.
+       Output them with output_constant_def below unless we're sure
+       they're zeros.  This should go away when vector initializers
+       are treated like VECTOR_CST instead of arrays.
+      */
       else if ((TREE_STATIC (exp)
                && ((mode == BLKmode
                     && ! (target != 0 && safe_from_p (target, exp, 1)))
@@ -6577,7 +6785,9 @@ expand_expr (exp, target, tmode, modifier)
                        && (! MOVE_BY_PIECES_P
                            (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
                             TYPE_ALIGN (type)))
-                       && ! mostly_zeros_p (exp))))
+                       && ((TREE_CODE (type) == VECTOR_TYPE
+                            && !is_zeros_p (exp))
+                           || ! mostly_zeros_p (exp)))))
               || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
        {
          rtx constructor = output_constant_def (exp, 1);
@@ -6614,15 +6824,15 @@ expand_expr (exp, target, tmode, modifier)
        tree string = string_constant (exp1, &index);
 
        /* Try to optimize reads from const strings.  */
-       if (string
-           && TREE_CODE (string) == STRING_CST
-           && TREE_CODE (index) == INTEGER_CST
+       if (string
+           && TREE_CODE (string) == STRING_CST
+           && TREE_CODE (index) == INTEGER_CST
            && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
-           && GET_MODE_CLASS (mode) == MODE_INT
-           && GET_MODE_SIZE (mode) == 1
+           && GET_MODE_CLASS (mode) == MODE_INT
+           && GET_MODE_SIZE (mode) == 1
            && modifier != EXPAND_WRITE)
-         return
-           GEN_INT (TREE_STRING_POINTER (string)[TREE_INT_CST_LOW (index)]);
+         return gen_int_mode (TREE_STRING_POINTER (string)
+                              [TREE_INT_CST_LOW (index)], mode);
 
        op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        op0 = memory_address (mode, op0);
@@ -6671,8 +6881,8 @@ expand_expr (exp, target, tmode, modifier)
            && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
            && GET_MODE_CLASS (mode) == MODE_INT
            && GET_MODE_SIZE (mode) == 1)
-         return
-           GEN_INT (TREE_STRING_POINTER (array)[TREE_INT_CST_LOW (index)]);
+         return gen_int_mode (TREE_STRING_POINTER (array)
+                              [TREE_INT_CST_LOW (index)], mode);
 
        /* If this is a constant index into a constant array,
           just get the value from the array.  Handle both the cases when
@@ -6732,9 +6942,8 @@ expand_expr (exp, target, tmode, modifier)
 
                    if (GET_MODE_CLASS (mode) == MODE_INT
                        && GET_MODE_SIZE (mode) == 1)
-                     return (GEN_INT
-                             (TREE_STRING_POINTER
-                              (init)[TREE_INT_CST_LOW (index)]));
+                     return gen_int_mode (TREE_STRING_POINTER (init)
+                                          [TREE_INT_CST_LOW (index)], mode);
                  }
              }
          }
@@ -6876,12 +7085,12 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (op0) != MEM)
              abort ();
 
-           if (GET_MODE (offset_rtx) != ptr_mode)
-             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
 #ifdef POINTERS_EXTEND_UNSIGNED
            if (GET_MODE (offset_rtx) != Pmode)
              offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+           if (GET_MODE (offset_rtx) != ptr_mode)
+             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
            /* A constant address in OP0 can have VOIDmode, we must not try
@@ -6902,6 +7111,12 @@ expand_expr (exp, target, tmode, modifier)
                                  highest_pow2_factor (offset));
          }
 
+       /* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
+          record its alignment as BIGGEST_ALIGNMENT.  */
+       if (GET_CODE (op0) == MEM && bitpos == 0 && offset != 0
+           && is_aligning_offset (offset, tem))
+         set_mem_align (op0, BIGGEST_ALIGNMENT);
+
        /* Don't forget about volatility even if this is a bitfield.  */
        if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
          {
@@ -6911,6 +7126,16 @@ expand_expr (exp, target, tmode, modifier)
            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)
+         {
+           if (bitpos != 0 || bitsize != GET_MODE_BITSIZE (GET_MODE (op0)))
+             abort ();
+           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
@@ -6991,7 +7216,8 @@ expand_expr (exp, target, tmode, modifier)
            if (mode == BLKmode)
              {
                rtx new = assign_temp (build_qualified_type
-                                      (type_for_mode (ext_mode, 0),
+                                      ((*lang_hooks.types.type_for_mode)
+                                       (ext_mode, 0),
                                        TYPE_QUAL_CONST), 0, 1, 1);
 
                emit_move_insn (new, op0);
@@ -7183,7 +7409,8 @@ expand_expr (exp, target, tmode, modifier)
        {
          WITH_CLEANUP_EXPR_RTL (exp)
            = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-         expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 1));
+         expand_decl_cleanup_eh (NULL_TREE, TREE_OPERAND (exp, 1),
+                                 CLEANUP_EH_ONLY (exp));
 
          /* That's it for this cleanup.  */
          TREE_OPERAND (exp, 1) = 0;
@@ -7213,10 +7440,11 @@ expand_expr (exp, target, tmode, modifier)
          && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == FUNCTION_DECL)
          && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-        {
+       {
          if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == BUILT_IN_FRONTEND)
-           return (*lang_expand_expr) (exp, original_target, tmode, modifier);
+           return (*lang_hooks.expand_expr)
+             (exp, original_target, tmode, modifier);
          else
            return expand_builtin (exp, target, subtarget, tmode, ignore);
        }
@@ -7295,7 +7523,7 @@ expand_expr (exp, target, tmode, modifier)
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
          enum machine_mode inner_mode = TYPE_MODE (inner_type);
 
-          if (modifier == EXPAND_INITIALIZER)
+         if (modifier == EXPAND_INITIALIZER)
            return simplify_gen_subreg (mode, op0, inner_mode,
                                        subreg_lowpart_offset (mode,
                                                               inner_mode));
@@ -7382,7 +7610,7 @@ expand_expr (exp, target, tmode, modifier)
 
              op0 = new;
            }
-      
+
          op0 = adjust_address (op0, TYPE_MODE (type), 0);
        }
 
@@ -7429,7 +7657,7 @@ expand_expr (exp, target, tmode, modifier)
 
         If this is an EXPAND_SUM call, always return the sum.  */
       if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
-          || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
+         || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
        {
          if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
@@ -7460,7 +7688,8 @@ expand_expr (exp, target, tmode, modifier)
              rtx constant_part;
 
              op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
-                                EXPAND_SUM);
+                                (modifier == EXPAND_INITIALIZER
+                                ? EXPAND_INITIALIZER : EXPAND_SUM));
              if (! CONSTANT_P (op0))
                {
                  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
@@ -7606,23 +7835,20 @@ expand_expr (exp, target, tmode, modifier)
         indexed address, for machines that support that.  */
 
       if (modifier == EXPAND_SUM && mode == ptr_mode
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+         && host_integerp (TREE_OPERAND (exp, 1), 0))
        {
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
                             EXPAND_SUM);
 
-         /* Apply distributive law if OP0 is x+c.  */
-         if (GET_CODE (op0) == PLUS
-             && GET_CODE (XEXP (op0, 1)) == CONST_INT)
-           return
-             gen_rtx_PLUS
-               (mode,
-                gen_rtx_MULT
-                (mode, XEXP (op0, 0),
-                 GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
-                GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
-                         * INTVAL (XEXP (op0, 1))));
+         /* If we knew for certain that this is arithmetic for an array
+            reference, and we knew the bounds of the array, then we could
+            apply the distributive law across (PLUS X C) for constant C.
+            Without such knowledge, we risk overflowing the computation
+            when both X and C are large, but X+C isn't.  */
+         /* ??? Could perhaps special-case EXP being unsigned and C being
+            positive.  In that case we are certain that X+C is no smaller
+            than X and so the transformed expression will overflow iff the
+            original would have.  */
 
          if (GET_CODE (op0) != REG)
            op0 = force_operand (op0, NULL_RTX);
@@ -7631,7 +7857,7 @@ expand_expr (exp, target, tmode, modifier)
 
          return
            gen_rtx_MULT (mode, op0,
-                         GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
+                         GEN_INT (tree_low_cst (TREE_OPERAND (exp, 1), 0)));
        }
 
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
@@ -7732,6 +7958,7 @@ expand_expr (exp, target, tmode, modifier)
          expensive divide.  If not, combine will rebuild the original
          computation.  */
       if (flag_unsafe_math_optimizations && optimize && !optimize_size
+         && TREE_CODE (type) == REAL_TYPE
          && !real_onep (TREE_OPERAND (exp, 0)))
         return expand_expr (build (MULT_EXPR, type, TREE_OPERAND (exp, 0),
                                   build (RDIV_EXPR, type,
@@ -7779,9 +8006,9 @@ expand_expr (exp, target, tmode, modifier)
     case NEGATE_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
       temp = expand_unop (mode,
-                          ! unsignedp && flag_trapv
-                          && (GET_MODE_CLASS(mode) == MODE_INT)
-                          ? negv_optab : neg_optab, op0, target, 0);
+                         ! unsignedp && flag_trapv
+                         && (GET_MODE_CLASS(mode) == MODE_INT)
+                         ? negv_optab : neg_optab, op0, target, 0);
       if (temp == 0)
        abort ();
       return temp;
@@ -7941,8 +8168,25 @@ expand_expr (exp, target, tmode, modifier)
          temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
                              VOIDmode, 0);
 
+         /* 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)
-           temp = copy_to_reg (temp);
+           {
+             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,
@@ -8120,13 +8364,13 @@ expand_expr (exp, target, tmode, modifier)
          {
            rtx result;
            optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
-                            ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
-                               ? addv_optab : add_optab)
-                            : TREE_CODE (binary_op) == MINUS_EXPR
-                              ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
-                                 ? subv_optab : sub_optab)
-                            : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
-                            : xor_optab);
+                           ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
+                              ? addv_optab : add_optab)
+                           : TREE_CODE (binary_op) == MINUS_EXPR
+                           ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
+                              ? subv_optab : sub_optab)
+                           : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
+                           : xor_optab);
 
            /* If we had X ? A : A + 1, do this as A + (X == 0).
 
@@ -8340,7 +8584,8 @@ expand_expr (exp, target, tmode, modifier)
                   built here.  */
 
                if (TREE_OPERAND (exp, 2) == 0)
-                 TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
+                 TREE_OPERAND (exp, 2)
+                   = (*lang_hooks.maybe_build_cleanup) (slot);
                cleanups = TREE_OPERAND (exp, 2);
              }
          }
@@ -8378,7 +8623,7 @@ expand_expr (exp, target, tmode, modifier)
 
        store_expr (exp1, target, 0);
 
-       expand_decl_cleanup (NULL_TREE, cleanups);
+       expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
 
        return target;
       }
@@ -8440,7 +8685,7 @@ expand_expr (exp, target, tmode, modifier)
          }
 
        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
-       
+
        return temp;
       }
 
@@ -8529,11 +8774,11 @@ expand_expr (exp, target, tmode, modifier)
                    /* Handle calls that pass values in multiple
                       non-contiguous locations.  The Irix 6 ABI has examples
                       of this.  */
-                   emit_group_store (memloc, op0, 
+                   emit_group_store (memloc, op0,
                                      int_size_in_bytes (inner_type));
                  else
                    emit_move_insn (memloc, op0);
-                 
+
                  op0 = memloc;
                }
            }
@@ -8639,7 +8884,7 @@ expand_expr (exp, target, tmode, modifier)
        if (GET_CODE (target) != CONCAT)
          emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
        else
-         emit_insns (insns);
+         emit_insn (insns);
 
        return target;
       }
@@ -8671,9 +8916,9 @@ expand_expr (exp, target, tmode, modifier)
 
        imag_t = gen_imagpart (partmode, target);
        temp = expand_unop (partmode,
-                            ! unsignedp && flag_trapv
-                            && (GET_MODE_CLASS(partmode) == MODE_INT)
-                            ? negv_optab : neg_optab,
+                           ! unsignedp && flag_trapv
+                           && (GET_MODE_CLASS(partmode) == MODE_INT)
+                           ? negv_optab : neg_optab,
                            gen_imagpart (partmode, op0), imag_t, 0);
        if (temp != imag_t)
          emit_move_insn (imag_t, temp);
@@ -8688,7 +8933,7 @@ expand_expr (exp, target, tmode, modifier)
        if (GET_CODE (target) != CONCAT)
          emit_no_conflict_block (insns, target, op0, NULL_RTX, NULL_RTX);
        else
-         emit_insns (insns);
+         emit_insn (insns);
 
        return target;
       }
@@ -8710,29 +8955,55 @@ expand_expr (exp, target, tmode, modifier)
       {
        tree try_block = TREE_OPERAND (exp, 0);
        tree finally_block = TREE_OPERAND (exp, 1);
-       rtx finally_label = gen_label_rtx ();
-       rtx done_label = gen_label_rtx ();
-       rtx return_link = gen_reg_rtx (Pmode);
-       tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
-                             (tree) finally_label, (tree) return_link);
-       TREE_SIDE_EFFECTS (cleanup) = 1;
 
-       /* Start a new binding layer that will keep track of all cleanup
-          actions to be performed.  */
-       expand_start_bindings (2);
+        if (!optimize || unsafe_for_reeval (finally_block) > 1)
+         {
+           /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
+              is not sufficient, so we cannot expand the block twice.
+              So we play games with GOTO_SUBROUTINE_EXPR to let us
+              expand the thing only once.  */
+           /* When not optimizing, we go ahead with this form since
+              (1) user breakpoints operate more predictably without
+                  code duplication, and
+              (2) we're not running any of the global optimizers
+                  that would explode in time/space with the highly
+                  connected CFG created by the indirect branching.  */
+
+           rtx finally_label = gen_label_rtx ();
+           rtx done_label = gen_label_rtx ();
+           rtx return_link = gen_reg_rtx (Pmode);
+           tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
+                                 (tree) finally_label, (tree) return_link);
+           TREE_SIDE_EFFECTS (cleanup) = 1;
+
+           /* Start a new binding layer that will keep track of all cleanup
+              actions to be performed.  */
+           expand_start_bindings (2);
+           target_temp_slot_level = temp_slot_level;
+
+           expand_decl_cleanup (NULL_TREE, cleanup);
+           op0 = expand_expr (try_block, target, tmode, modifier);
+
+           preserve_temp_slots (op0);
+           expand_end_bindings (NULL_TREE, 0, 0);
+           emit_jump (done_label);
+           emit_label (finally_label);
+           expand_expr (finally_block, const0_rtx, VOIDmode, 0);
+           emit_indirect_jump (return_link);
+           emit_label (done_label);
+         }
+       else
+         {
+           expand_start_bindings (2);
+           target_temp_slot_level = temp_slot_level;
 
-       target_temp_slot_level = temp_slot_level;
+           expand_decl_cleanup (NULL_TREE, finally_block);
+           op0 = expand_expr (try_block, target, tmode, modifier);
 
-       expand_decl_cleanup (NULL_TREE, cleanup);
-       op0 = expand_expr (try_block, target, tmode, modifier);
+           preserve_temp_slots (op0);
+           expand_end_bindings (NULL_TREE, 0, 0);
+         }
 
-       preserve_temp_slots (op0);
-       expand_end_bindings (NULL_TREE, 0, 0);
-       emit_jump (done_label);
-       emit_label (finally_label);
-       expand_expr (finally_block, const0_rtx, VOIDmode, 0);
-       emit_indirect_jump (return_link);
-       emit_label (done_label);
        return op0;
       }
 
@@ -8760,7 +9031,7 @@ expand_expr (exp, target, tmode, modifier)
       abort ();
 
     default:
-      return (*lang_expand_expr) (exp, original_target, tmode, modifier);
+      return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier);
     }
 
   /* Here to do an ordinary binary operator, generating an instruction
@@ -8778,7 +9049,57 @@ expand_expr (exp, target, tmode, modifier)
   return temp;
 }
 \f
-/* Return the tree node if a ARG corresponds to a string constant or zero
+/* Subroutine of above: returns 1 if OFFSET corresponds to an offset that
+   when applied to the address of EXP produces an address known to be
+   aligned more than BIGGEST_ALIGNMENT.  */
+
+static int
+is_aligning_offset (offset, exp)
+     tree offset;
+     tree exp;
+{
+  /* Strip off any conversions and WITH_RECORD_EXPR nodes.  */
+  while (TREE_CODE (offset) == NON_LVALUE_EXPR
+        || TREE_CODE (offset) == NOP_EXPR
+        || TREE_CODE (offset) == CONVERT_EXPR
+        || TREE_CODE (offset) == WITH_RECORD_EXPR)
+    offset = TREE_OPERAND (offset, 0);
+
+  /* We must now have a BIT_AND_EXPR with a constant that is one less than
+     power of 2 and which is larger than BIGGEST_ALIGNMENT.  */
+  if (TREE_CODE (offset) != BIT_AND_EXPR
+      || !host_integerp (TREE_OPERAND (offset, 1), 1)
+      || compare_tree_int (TREE_OPERAND (offset, 1), BIGGEST_ALIGNMENT) <= 0
+      || !exact_log2 (tree_low_cst (TREE_OPERAND (offset, 1), 1) + 1) < 0)
+    return 0;
+
+  /* Look at the first operand of BIT_AND_EXPR and strip any conversion.
+     It must be NEGATE_EXPR.  Then strip any more conversions.  */
+  offset = TREE_OPERAND (offset, 0);
+  while (TREE_CODE (offset) == NON_LVALUE_EXPR
+        || TREE_CODE (offset) == NOP_EXPR
+        || TREE_CODE (offset) == CONVERT_EXPR)
+    offset = TREE_OPERAND (offset, 0);
+
+  if (TREE_CODE (offset) != NEGATE_EXPR)
+    return 0;
+
+  offset = TREE_OPERAND (offset, 0);
+  while (TREE_CODE (offset) == NON_LVALUE_EXPR
+        || TREE_CODE (offset) == NOP_EXPR
+        || TREE_CODE (offset) == CONVERT_EXPR)
+    offset = TREE_OPERAND (offset, 0);
+
+  /* This must now be the address either of EXP or of a PLACEHOLDER_EXPR
+     whose type is the same as EXP.  */
+  return (TREE_CODE (offset) == ADDR_EXPR
+         && (TREE_OPERAND (offset, 0) == exp
+             || (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
+                 && (TREE_TYPE (TREE_OPERAND (offset, 0))
+                     == TREE_TYPE (exp)))));
+}
+\f
+/* Return the tree node if an ARG corresponds to a string constant or zero
    if it doesn't.  If we return non-zero, set *PTR_OFFSET to the offset
    in bytes within the string that ARG is accessing.  The type of the
    offset will be `sizetype'.  */
@@ -9211,7 +9532,7 @@ do_jump (exp, if_false_label, if_true_label)
          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
-         && (type = type_for_mode (mode, 1)) != 0
+         && (type = (*lang_hooks.types.type_for_mode) (mode, 1)) != 0
          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
          && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
              != CODE_FOR_nothing))
@@ -9271,7 +9592,7 @@ do_jump (exp, if_false_label, if_true_label)
        get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
                             &unsignedp, &volatilep);
 
-       type = type_for_size (bitsize, unsignedp);
+       type = (*lang_hooks.types.type_for_size) (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
            && type != 0 && bitsize >= 0
            && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
@@ -9454,7 +9775,7 @@ do_jump (exp, if_false_label, if_true_label)
                || rcmp == UNORDERED))
          do_rev = 1;
 
-        if (! do_rev)
+       if (! do_rev)
          do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
        else
          do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
@@ -9487,7 +9808,7 @@ do_jump (exp, if_false_label, if_true_label)
        goto unordered_bcc;
 
       unordered_bcc:
-        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        if (can_compare_p (rcode1, mode, ccp_jump))
          do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
                               if_true_label);
@@ -9556,7 +9877,7 @@ do_jump (exp, if_false_label, if_true_label)
       /* Do any postincrements in the expression that was tested.  */
       emit_queue ();
 
-      if (GET_CODE (temp) == CONST_INT 
+      if (GET_CODE (temp) == CONST_INT
          || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
          || GET_CODE (temp) == LABEL_REF)
        {
@@ -9759,6 +10080,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size)
      enum machine_mode mode;
      rtx size;
 {
+  enum rtx_code ucode;
   rtx tem;
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -9780,8 +10102,8 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size)
 
   do_pending_stack_adjust ();
 
-  if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
-      && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
+  ucode = unsignedp ? unsigned_condition (code) : code;
+  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
     return tem;
 
 #if 0
@@ -9808,7 +10130,11 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size)
 
   emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
 
+#if HAVE_cc0
   return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
+#else
+  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+#endif
 }
 
 /* Like do_compare_and_jump but expects the values to compare as two rtx's.
@@ -9827,6 +10153,7 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
      rtx size;
      rtx if_false_label, if_true_label;
 {
+  enum rtx_code ucode;
   rtx tem;
   int dummy_true_label = 0;
 
@@ -9858,8 +10185,8 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
 
   do_pending_stack_adjust ();
 
-  if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
-      && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
+  ucode = unsignedp ? unsigned_condition (code) : code;
+  if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
     {
       if (tem == const_true_rtx)
        {
@@ -10352,8 +10679,8 @@ try_casesi (index_type, index_expr, minval, range,
     {
       if (TYPE_MODE (index_type) != index_mode)
        {
-         index_expr = convert (type_for_size (index_bits, 0),
-                               index_expr);
+         index_expr = convert ((*lang_hooks.types.type_for_size)
+                               (index_bits, 0), index_expr);
          index_type = TREE_TYPE (index_expr);
        }
 
@@ -10498,3 +10825,35 @@ try_tablejump (index_type, index_expr, minval, range,
                table_label, default_label);
   return 1;
 }
+
+/* Nonzero if the mode is a valid vector mode for this architecture.
+   This returns nonzero even if there is no hardware support for the
+   vector mode, but we can emulate with narrower modes.  */
+
+int
+vector_mode_valid_p (mode)
+     enum machine_mode mode;
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode innermode;
+
+  /* Doh!  What's going on?  */
+  if (class != MODE_VECTOR_INT
+      && class != MODE_VECTOR_FLOAT)
+    return 0;
+
+  /* Hardware support.  Woo hoo!  */
+  if (VECTOR_MODE_SUPPORTED_P (mode))
+    return 1;
+
+  innermode = GET_MODE_INNER (mode);
+
+  /* We should probably return 1 if requesting V4DI and we have no DI,
+     but we have V2DI, but this is probably very unlikely.  */
+
+  /* If we have support for the inner mode, we can safely emulate it.
+     We may not have V2DI, but me can emulate with a pair of DIs.  */
+  return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
+}
+
+#include "gt-expr.h"