OSDN Git Service

2002-04-02 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 5884217..6f1a0d6 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc.
+   2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -1052,6 +1052,9 @@ convert_move (to, from, unsignedp)
       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
          != CODE_FOR_nothing)
        {
+         if (flag_force_mem)
+           from = force_not_mem (from);
+
          emit_unop_insn (code, to, from, equiv_code);
          return;
        }
@@ -1349,7 +1352,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);
@@ -1572,9 +1575,11 @@ move_by_pieces_1 (genfun, mode, data)
        from1 = adjust_address (data->from, mode, data->offset);
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
-       emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+       emit_insn (gen_add2_insn (data->to_addr,
+                                 GEN_INT (-(HOST_WIDE_INT)size)));
       if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
-       emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
+       emit_insn (gen_add2_insn (data->from_addr,
+                                 GEN_INT (-(HOST_WIDE_INT)size)));
 
       if (data->to)
        emit_insn ((*genfun) (to1, from1));
@@ -1999,12 +2004,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),
@@ -2090,7 +2100,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.  */
@@ -2103,6 +2113,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)
@@ -2116,14 +2127,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);
     }
 
@@ -2788,7 +2812,6 @@ emit_move_insn_1 (x, y)
   enum machine_mode mode = GET_MODE (x);
   enum machine_mode submode;
   enum mode_class class = GET_MODE_CLASS (mode);
-  unsigned int i;
 
   if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
     abort ();
@@ -2814,10 +2837,11 @@ emit_move_insn_1 (x, y)
       /* In case we output to the stack, but the size is smaller machine can
         push exactly, we need to use move instructions.  */
       if (stack
-         && PUSH_ROUNDING (GET_MODE_SIZE (submode)) != GET_MODE_SIZE (submode))
+         && (PUSH_ROUNDING (GET_MODE_SIZE (submode))
+             != GET_MODE_SIZE (submode)))
        {
          rtx temp;
-         int offset1, offset2;
+         HOST_WIDE_INT offset1, offset2;
 
          /* Do not use anti_adjust_stack, since we don't want to update
             stack_pointer_delta.  */
@@ -2829,12 +2853,13 @@ emit_move_insn_1 (x, y)
 #endif
                               stack_pointer_rtx,
                               GEN_INT
-                                (PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))),
-                              stack_pointer_rtx,
-                              0,
-                              OPTAB_LIB_WIDEN);
+                                (PUSH_ROUNDING
+                                 (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);
+
 #ifdef STACK_GROWS_DOWNWARD
          offset1 = 0;
          offset2 = GET_MODE_SIZE (submode);
@@ -2843,6 +2868,7 @@ emit_move_insn_1 (x, y)
          offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
                     + GET_MODE_SIZE (submode));
 #endif
+
          emit_move_insn (change_address (x, submode,
                                          gen_rtx_PLUS (Pmode,
                                                        stack_pointer_rtx,
@@ -2898,8 +2924,10 @@ emit_move_insn_1 (x, y)
          if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
              && (reload_in_progress | reload_completed) == 0)
            {
-             int packed_dest_p = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
-             int packed_src_p  = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
+             int packed_dest_p
+               = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
+             int packed_src_p
+               = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
 
              if (packed_dest_p || packed_src_p)
                {
@@ -2921,12 +2949,14 @@ emit_move_insn_1 (x, y)
                      if (packed_dest_p)
                        {
                          rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
+
                          emit_move_insn_1 (cmem, y);
                          return emit_move_insn_1 (sreg, mem);
                        }
                      else
                        {
                          rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
+
                          emit_move_insn_1 (mem, sreg);
                          return emit_move_insn_1 (x, cmem);
                        }
@@ -2947,9 +2977,7 @@ emit_move_insn_1 (x, y)
              && ! (reload_in_progress || reload_completed)
              && (GET_CODE (realpart_x) == SUBREG
                  || GET_CODE (imagpart_x) == SUBREG))
-           {
-             emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
-           }
+           emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
 
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
                     (realpart_x, realpart_y));
@@ -2968,6 +2996,7 @@ emit_move_insn_1 (x, y)
       rtx last_insn = 0;
       rtx seq, inner;
       int need_clobber;
+      int i;
 
 #ifdef PUSH_ROUNDING
 
@@ -2988,19 +3017,20 @@ emit_move_insn_1 (x, y)
 #endif
                               stack_pointer_rtx,
                               GEN_INT
-                                (PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))),
-                              stack_pointer_rtx,
-                              0,
-                              OPTAB_LIB_WIDEN);
+                                (PUSH_ROUNDING
+                                 (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);
 
          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, 
-                               GEN_INT (-(HOST_WIDE_INT)
-                                          GET_MODE_SIZE (GET_MODE (x))));
+                               GEN_INT (-((HOST_WIDE_INT)
+                                          GET_MODE_SIZE (GET_MODE (x)))));
          else if (code == POST_DEC)
            temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 
                                GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
@@ -3059,9 +3089,7 @@ emit_move_insn_1 (x, y)
       if (x != y
          && ! (reload_in_progress || reload_completed)
          && need_clobber != 0)
-       {
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
-       }
+       emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
 
       emit_insn (seq);
 
@@ -3152,7 +3180,7 @@ emit_single_push_insn (mode, x, type)
   if (icode != CODE_FOR_nothing)
     {
       if (((pred = insn_data[(int) icode].operand[0].predicate)
-         && !((*pred) (x, mode))))
+          && !((*pred) (x, mode))))
        x = force_reg (mode, x);
       emit_insn (GEN_FCN (icode) (x));
       return;
@@ -3163,7 +3191,7 @@ emit_single_push_insn (mode, x, type)
     {
 #ifdef STACK_GROWS_DOWNWARD
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                               GEN_INT (-(HOST_WIDE_INT)rounded_size));
+                               GEN_INT (-(HOST_WIDE_INT) rounded_size));
 #else
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (rounded_size));
@@ -3650,7 +3678,7 @@ expand_assignment (to, from, want_value, suggest_reg)
 
       if (offset != 0)
        {
-         rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+         rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 
          if (GET_CODE (to_rtx) != MEM)
            abort ();
@@ -3673,15 +3701,7 @@ expand_assignment (to, from, want_value, suggest_reg)
              && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
              && MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
            {
-             rtx temp
-               = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
-
-             if (GET_CODE (XEXP (temp, 0)) == REG)
-               to_rtx = temp;
-             else
-               to_rtx = (replace_equiv_address
-                         (to_rtx, force_reg (GET_MODE (XEXP (temp, 0)),
-                                             XEXP (temp, 0))));
+             to_rtx = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
              bitpos = 0;
            }
 
@@ -3727,7 +3747,7 @@ expand_assignment (to, from, want_value, suggest_reg)
          RTX_UNCHANGING_P (to_rtx) = 1;
        }
 
-      if (! can_address_p (to))
+      if (GET_CODE (to_rtx) == MEM && ! can_address_p (to))
        {
          if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
@@ -3988,6 +4008,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
@@ -3999,18 +4021,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
@@ -4038,13 +4061,19 @@ store_expr (exp, target, want_value)
         target.  Otherwise, the caller might get confused by a result whose
         mode is larger than expected.  */
 
-      if (want_value && GET_MODE (temp) != GET_MODE (target)
-         && GET_MODE (temp) != VOIDmode)
+      if (want_value && GET_MODE (temp) != GET_MODE (target))
        {
-         temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
-         SUBREG_PROMOTED_VAR_P (temp) = 1;
-         SUBREG_PROMOTED_UNSIGNED_P (temp)
-           = SUBREG_PROMOTED_UNSIGNED_P (target);
+         if (GET_MODE (temp) != VOIDmode)
+           {
+             temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
+             SUBREG_PROMOTED_VAR_P (temp) = 1;
+             SUBREG_PROMOTED_UNSIGNED_SET (temp, 
+               SUBREG_PROMOTED_UNSIGNED_P (target));
+           }
+         else
+           temp = convert_modes (GET_MODE (target),
+                                 GET_MODE (SUBREG_REG (target)),
+                                 temp, SUBREG_PROMOTED_UNSIGNED_P (target));
        }
 
       return want_value ? temp : NULL_RTX;
@@ -4229,6 +4258,14 @@ is_zeros_p (exp)
     case REAL_CST:
       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
 
+    case VECTOR_CST:
+      for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
+          elt = TREE_CHAIN (elt))
+       if (!is_zeros_p (TREE_VALUE (elt)))
+         return 0;
+
+      return 1;
+
     case CONSTRUCTOR:
       if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
@@ -4488,7 +4525,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);
                }
 
@@ -4513,20 +4551,34 @@ store_constructor (exp, target, cleared, size)
                                   get_alias_set (TREE_TYPE (field)));
        }
     }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
+  else if (TREE_CODE (type) == ARRAY_TYPE
+          || TREE_CODE (type) == VECTOR_TYPE)
     {
       tree elt;
       int i;
       int need_to_clear;
       tree domain = TYPE_DOMAIN (type);
       tree elttype = TREE_TYPE (type);
-      int const_bounds_p = (TYPE_MIN_VALUE (domain)
-                           && TYPE_MAX_VALUE (domain)
-                           && host_integerp (TYPE_MIN_VALUE (domain), 0)
-                           && host_integerp (TYPE_MAX_VALUE (domain), 0));
+      int const_bounds_p;
       HOST_WIDE_INT minelt = 0;
       HOST_WIDE_INT maxelt = 0;
 
+      /* Vectors are like arrays, but the domain is stored via an array
+        type indirectly.  */
+      if (TREE_CODE (type) == VECTOR_TYPE)
+       {
+         /* Note that although TYPE_DEBUG_REPRESENTATION_TYPE uses
+            the same field as TYPE_DOMAIN, we are not guaranteed that
+            it always will.  */
+         domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
+         domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
+       }
+
+      const_bounds_p = (TYPE_MIN_VALUE (domain)
+                       && TYPE_MAX_VALUE (domain)
+                       && host_integerp (TYPE_MIN_VALUE (domain), 0)
+                       && host_integerp (TYPE_MAX_VALUE (domain), 0));
+
       /* If we have constant bounds for the range of the type, get them.  */
       if (const_bounds_p)
        {
@@ -4587,7 +4639,12 @@ store_constructor (exp, target, cleared, size)
       if (need_to_clear && size > 0)
        {
          if (! cleared)
-           clear_storage (target, GEN_INT (size));
+           {
+             if (REG_P (target))
+               emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+             else
+               clear_storage (target, GEN_INT (size));
+           }
          cleared = 1;
        }
       else if (REG_P (target))
@@ -4650,6 +4707,7 @@ store_constructor (exp, target, cleared, size)
 
                      if (GET_CODE (target) == MEM
                          && !MEM_KEEP_ALIAS_SET_P (target)
+                         && TREE_CODE (type) == ARRAY_TYPE
                          && TYPE_NONALIASED_COMPONENT (type))
                        {
                          target = copy_rtx (target);
@@ -4747,6 +4805,7 @@ store_constructor (exp, target, cleared, size)
                bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
 
              if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
+                 && TREE_CODE (type) == ARRAY_TYPE
                  && TYPE_NONALIASED_COMPONENT (type))
                {
                  target = copy_rtx (target);
@@ -4896,7 +4955,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);
@@ -5003,9 +5063,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
        = assign_temp
          (build_qualified_type (type, TYPE_QUALS (type) | TYPE_QUAL_CONST),
           0, 1, 1);
-      rtx blk_object = copy_rtx (object);
-
-      PUT_MODE (blk_object, BLKmode);
+      rtx blk_object = adjust_address (object, BLKmode, 0);
 
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
@@ -5101,18 +5159,15 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
              tree count;
              enum machine_mode tmode;
 
-             if (unsignedp)
-               return expand_and (temp,
-                                  GEN_INT
-                                  (trunc_int_for_mode
-                                   (width_mask,
-                                    GET_MODE (temp) == VOIDmode
-                                    ? value_mode
-                                    : GET_MODE (temp))), NULL_RTX);
-
              tmode = GET_MODE (temp);
              if (tmode == VOIDmode)
                tmode = value_mode;
+
+             if (unsignedp)
+               return expand_and (tmode, temp,
+                                  gen_int_mode (width_mask, tmode),
+                                  NULL_RTX);
+
              count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
              temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
              return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
@@ -5380,8 +5435,7 @@ force_operand (value, target)
   rtx subtarget = get_subtarget (target);
 
   /* Check for a PIC address load.  */
-  if (flag_pic
-      && (GET_CODE (value) == PLUS || GET_CODE (value) == MINUS)
+  if ((GET_CODE (value) == PLUS || GET_CODE (value) == MINUS)
       && XEXP (value, 0) == pic_offset_table_rtx
       && (GET_CODE (XEXP (value, 1)) == SYMBOL_REF
          || GET_CODE (XEXP (value, 1)) == LABEL_REF
@@ -5699,7 +5753,7 @@ safe_from_p (x, exp, top_p)
         are memory and they conflict.  */
       return ! (rtx_equal_p (x, exp_rtl)
                || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
-                   && true_dependence (exp_rtl, GET_MODE (x), x,
+                   && true_dependence (exp_rtl, VOIDmode, x,
                                        rtx_addr_varies_p)));
     }
 
@@ -5792,19 +5846,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, pessimize by
-        returning 1.  This is overly-conservative, but such things should not
-        happen in the offset expressions that we are called with.  If
-        the constant overlows, we some erroneous program, so return
-        BIGGEST_ALIGNMENT to avoid any later ICE.  */
+      /* 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))
        return BIGGEST_ALIGNMENT;
-      else if (host_integerp (exp, 0))
+      else
        {
-         c0 = tree_low_cst (exp, 0);
-         c0 = c0 < 0 ? - c0 : c0;
-         return c0 != 0 ? c0 & -c0 : 1;
+         /* 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;
 
@@ -6150,7 +6206,7 @@ expand_expr (exp, target, tmode, modifier)
              set_mem_attributes (value, exp, 1);
              SET_DECL_RTL (exp, value);
            }
-         }
+       }
 
       /* ... fall through ...  */
 
@@ -6191,7 +6247,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);
@@ -6248,12 +6304,13 @@ 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;
        }
 
@@ -6373,7 +6430,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)
@@ -6395,7 +6452,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;
        }
 
@@ -6405,7 +6462,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;
       }
 
@@ -6451,7 +6509,7 @@ expand_expr (exp, target, tmode, modifier)
 
     case LABELED_BLOCK_EXPR:
       if (LABELED_BLOCK_BODY (exp))
-       expand_expr_stmt (LABELED_BLOCK_BODY (exp));
+       expand_expr_stmt_value (LABELED_BLOCK_BODY (exp), 0, 1);
       /* Should perhaps use expand_label, but this is simpler and safer.  */
       do_pending_stack_adjust ();
       emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
@@ -6466,7 +6524,7 @@ expand_expr (exp, target, tmode, modifier)
     case LOOP_EXPR:
       push_temp_slots ();
       expand_start_loop (1);
-      expand_expr_stmt (TREE_OPERAND (exp, 0));
+      expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
       expand_end_loop ();
       pop_temp_slots ();
 
@@ -6484,7 +6542,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)
@@ -6589,8 +6647,8 @@ expand_expr (exp, target, tmode, modifier)
            && 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);
@@ -6639,8 +6697,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
@@ -6700,9 +6758,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);
                  }
              }
          }
@@ -6743,16 +6800,16 @@ expand_expr (exp, target, tmode, modifier)
                  {
                    HOST_WIDE_INT bitsize
                      = TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
+                   enum machine_mode imode
+                     = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
 
                    if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
                      {
                        op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
-                       op0 = expand_and (op0, op1, target);
+                       op0 = expand_and (imode, op0, op1, target);
                      }
                    else
                      {
-                       enum machine_mode imode
-                         = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
                        tree count
                          = build_int_2 (GET_MODE_BITSIZE (imode) - bitsize,
                                         0);
@@ -6812,7 +6869,7 @@ expand_expr (exp, target, tmode, modifier)
 
        if (offset != 0)
          {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 
            /* If this object is in a register, put it into memory.
               This case can't occur in C, but can in Ada if we have
@@ -6862,15 +6919,7 @@ expand_expr (exp, target, tmode, modifier)
                && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
                && MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
              {
-               rtx temp = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
-
-               if (GET_CODE (XEXP (temp, 0)) == REG)
-                 op0 = temp;
-               else
-                 op0 = (replace_equiv_address
-                        (op0,
-                         force_reg (GET_MODE (XEXP (temp, 0)),
-                                    XEXP (temp, 0))));
+               op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
                bitpos = 0;
              }
 
@@ -6967,7 +7016,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);
@@ -7192,7 +7242,8 @@ expand_expr (exp, target, tmode, modifier)
         {
          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);
        }
@@ -7261,15 +7312,24 @@ expand_expr (exp, target, tmode, modifier)
          return op0;
        }
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, 0);
+      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
       if (GET_MODE (op0) == mode)
        return op0;
 
       /* If OP0 is a constant, just convert it into the proper mode.  */
       if (CONSTANT_P (op0))
-       return
-         convert_modes (mode, TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
-                        op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+       {
+         tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+         enum machine_mode inner_mode = TYPE_MODE (inner_type);
+
+          if (modifier == EXPAND_INITIALIZER)
+           return simplify_gen_subreg (mode, op0, inner_mode,
+                                       subreg_lowpart_offset (mode,
+                                                              inner_mode));
+         else
+           return convert_modes (mode, inner_mode, op0,
+                                 TREE_UNSIGNED (inner_type));
+       }
 
       if (modifier == EXPAND_INITIALIZER)
        return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
@@ -7336,12 +7396,11 @@ expand_expr (exp, target, tmode, modifier)
                       (HOST_WIDE_INT) GET_MODE_SIZE (TYPE_MODE (type)));
              rtx new = assign_stack_temp_for_type (TYPE_MODE (type),
                                                    temp_size, 0, type);
-             rtx new_with_op0_mode = copy_rtx (new);
+             rtx new_with_op0_mode = adjust_address (new, GET_MODE (op0), 0);
 
              if (TREE_ADDRESSABLE (exp))
                abort ();
 
-             PUT_MODE (new_with_op0_mode, GET_MODE (op0));
              if (GET_MODE (op0) == BLKmode)
                emit_block_move (new_with_op0_mode, op0,
                                 GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))));
@@ -7351,7 +7410,7 @@ expand_expr (exp, target, tmode, modifier)
              op0 = new;
            }
       
-         PUT_MODE (op0, TYPE_MODE (type));
+         op0 = adjust_address (op0, TYPE_MODE (type), 0);
        }
 
       return op0;
@@ -7428,7 +7487,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,
@@ -7574,23 +7634,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);
@@ -7599,7 +7656,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))
@@ -7700,6 +7757,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,
@@ -7909,8 +7967,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,
@@ -8308,7 +8383,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);
              }
          }
@@ -8480,21 +8556,30 @@ expand_expr (exp, target, tmode, modifier)
                   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
                   || GET_CODE (op0) == PARALLEL)
            {
-             /* If this object is in a register, it must can't be BLKmode.  */
-             tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-             tree nt = build_qualified_type (inner_type,
-                                             (TYPE_QUALS (inner_type)
-                                              | TYPE_QUAL_CONST));
-             rtx memloc = assign_temp (nt, 1, 1, 1);
-
-             if (GET_CODE (op0) == PARALLEL)
-               /* Handle calls that pass values in multiple non-contiguous
-                  locations.  The Irix 6 ABI has examples of this.  */
-               emit_group_store (memloc, op0, int_size_in_bytes (inner_type));
+             /* If the operand is a SAVE_EXPR, we can deal with this by
+                forcing the SAVE_EXPR into memory.  */
+             if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
+               {
+                 put_var_into_stack (TREE_OPERAND (exp, 0));
+                 op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
+               }
              else
-               emit_move_insn (memloc, op0);
-
-             op0 = memloc;
+               {
+                 /* If this object is in a register, it can't be BLKmode.  */
+                 tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+                 rtx memloc = assign_temp (inner_type, 1, 1, 1);
+
+                 if (GET_CODE (op0) == PARALLEL)
+                   /* Handle calls that pass values in multiple
+                      non-contiguous locations.  The Irix 6 ABI has examples
+                      of this.  */
+                   emit_group_store (memloc, op0, 
+                                     int_size_in_bytes (inner_type));
+                 else
+                   emit_move_insn (memloc, op0);
+                 
+                 op0 = memloc;
+               }
            }
 
          if (GET_CODE (op0) != MEM)
@@ -8547,7 +8632,11 @@ expand_expr (exp, target, tmode, modifier)
          op0 = force_operand (XEXP (op0, 0), target);
        }
 
-      if (flag_force_addr && GET_CODE (op0) != REG)
+      if (flag_force_addr
+         && GET_CODE (op0) != REG
+         && modifier != EXPAND_CONST_ADDRESS
+         && modifier != EXPAND_INITIALIZER
+         && modifier != EXPAND_SUM)
        op0 = force_reg (Pmode, op0);
 
       if (GET_CODE (op0) == REG
@@ -8715,7 +8804,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
@@ -8866,7 +8955,7 @@ expand_increment (exp, post, ignore)
     }
 
   if (TYPE_TRAP_SIGNED (TREE_TYPE (exp)))
-     this_optab = this_optab == add_optab ? addv_optab : subv_optab;
+    this_optab = this_optab == add_optab ? addv_optab : subv_optab;
 
   /* For a preincrement, see if we can do this with a single instruction.  */
   if (!post)
@@ -9166,7 +9255,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))
@@ -9226,7 +9315,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))
@@ -10159,7 +10248,7 @@ do_store_flag (exp, target, mode, only_cheap)
 
       /* Put the AND last so it can combine with more things.  */
       if (bitnum != TYPE_PRECISION (type) - 1)
-       op0 = expand_and (op0, const1_rtx, subtarget);
+       op0 = expand_and (mode, op0, const1_rtx, subtarget);
 
       return op0;
     }
@@ -10230,6 +10319,14 @@ do_store_flag (exp, target, mode, only_cheap)
             || (result != const0_rtx && invert))
            ? const0_rtx : const1_rtx);
 
+  /* The code of RESULT may not match CODE if compare_from_rtx
+     decided to swap its operands and reverse the original code.
+
+     We know that compare_from_rtx returns either a CONST_INT or
+     a new comparison code, so it is safe to just extract the
+     code from RESULT.  */
+  code = GET_CODE (result);
+
   label = gen_label_rtx ();
   if (bcc_gen_fctn[(int) code] == 0)
     abort ();
@@ -10299,8 +10396,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);
        }