OSDN Git Service

fortran/
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 5961e27..92d8d28 100644 (file)
@@ -1,6 +1,7 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+   Inc.
 
 This file is part of GCC.
 
@@ -349,8 +350,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 {
   enum machine_mode to_mode = GET_MODE (to);
   enum machine_mode from_mode = GET_MODE (from);
-  int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
-  int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
+  int to_real = SCALAR_FLOAT_MODE_P (to_mode);
+  int from_real = SCALAR_FLOAT_MODE_P (from_mode);
   enum insn_code code;
   rtx libcall;
 
@@ -410,10 +411,15 @@ convert_move (rtx to, rtx from, int unsignedp)
       rtx value, insns;
       convert_optab tab;
 
-      gcc_assert (GET_MODE_PRECISION (from_mode)
-                 != GET_MODE_PRECISION (to_mode));
+      gcc_assert ((GET_MODE_PRECISION (from_mode)
+                  != GET_MODE_PRECISION (to_mode))
+                 || (DECIMAL_FLOAT_MODE_P (from_mode)
+                     != DECIMAL_FLOAT_MODE_P (to_mode)));
       
-      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+      if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
+       /* Conversion between decimal float and binary float, same size.  */
+       tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
+      else if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
        tab = sext_optab;
       else
        tab = trunc_optab;
@@ -1375,7 +1381,7 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
                      call_expr, arg_list, NULL_TREE);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
@@ -2522,7 +2528,7 @@ clear_storage_via_libcall (rtx object, rtx size, bool tailcall)
                      call_expr, arg_list, NULL_TREE);
   CALL_EXPR_TAILCALL (call_expr) = tailcall;
 
-  retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  retval = expand_normal (call_expr);
 
   return retval;
 }
@@ -2778,17 +2784,19 @@ emit_move_change_mode (enum machine_mode new_mode,
 {
   rtx ret;
 
-  if (reload_in_progress && MEM_P (x))
+  if (MEM_P (x))
     {
-      /* We can't use gen_lowpart here because it may call change_address
-        which is not appropriate if we were called when a reload was in
-        progress.  We don't have to worry about changing the address since
-        the size in bytes is supposed to be the same.  Copy the MEM to
-        change the mode and move any substitutions from the old MEM to
-        the new one.  */
-
-      ret = adjust_address_nv (x, new_mode, 0);
-      copy_replacements (x, ret);
+      /* We don't have to worry about changing the address since the
+        size in bytes is supposed to be the same.  */
+      if (reload_in_progress)
+       {
+         /* Copy the MEM to change the mode and move any
+            substitutions from the old MEM to the new one.  */
+         ret = adjust_address_nv (x, new_mode, 0);
+         copy_replacements (x, ret);
+       }
+      else
+       ret = adjust_address (x, new_mode, 0);
     }
   else
     {
@@ -2812,7 +2820,7 @@ emit_move_change_mode (enum machine_mode new_mode,
    emitted, or NULL if such a move could not be generated.  */
 
 static rtx
-emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
+emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
 {
   enum machine_mode imode;
   enum insn_code code;
@@ -2827,10 +2835,10 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y)
   if (code == CODE_FOR_nothing)
     return NULL_RTX;
 
-  x = emit_move_change_mode (imode, mode, x, false);
+  x = emit_move_change_mode (imode, mode, x, force);
   if (x == NULL_RTX)
     return NULL_RTX;
-  y = emit_move_change_mode (imode, mode, y, false);
+  y = emit_move_change_mode (imode, mode, y, force);
   if (y == NULL_RTX)
     return NULL_RTX;
   return emit_insn (GEN_FCN (code) (x, y));
@@ -2852,6 +2860,19 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
 #endif
   if (code == PRE_DEC || code == POST_DEC)
     adjust = -adjust;
+  else if (code == PRE_MODIFY || code == POST_MODIFY)
+    {
+      rtx expr = XEXP (XEXP (x, 0), 1);
+      HOST_WIDE_INT val;
+
+      gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
+      gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+      val = INTVAL (XEXP (expr, 1));
+      if (GET_CODE (expr) == MINUS)
+       val = -val;
+      gcc_assert (adjust == val || adjust == -val);
+      adjust = val;
+    }
 
   /* Do not use anti_adjust_stack, since we don't want to update
      stack_pointer_delta.  */
@@ -2865,13 +2886,13 @@ emit_move_resolve_push (enum machine_mode mode, rtx x)
     {
     case PRE_INC:
     case PRE_DEC:
+    case PRE_MODIFY:
       temp = stack_pointer_rtx;
       break;
     case POST_INC:
-      temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode));
-      break;
     case POST_DEC:
-      temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode));
+    case POST_MODIFY:
+      temp = plus_constant (stack_pointer_rtx, -adjust);
       break;
     default:
       gcc_unreachable ();
@@ -2973,7 +2994,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
          return get_last_insn ();
        }
 
-      ret = emit_move_via_integer (mode, x, y);
+      ret = emit_move_via_integer (mode, x, y, true);
       if (ret)
        return ret;
     }
@@ -3011,7 +3032,7 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
     }
 
   /* Otherwise, find the MODE_INT mode of the same width.  */
-  ret = emit_move_via_integer (mode, x, y);
+  ret = emit_move_via_integer (mode, x, y, false);
   gcc_assert (ret != NULL);
   return ret;
 }
@@ -3110,6 +3131,17 @@ emit_move_insn_1 (rtx x, rtx y)
   if (COMPLEX_MODE_P (mode))
     return emit_move_complex (mode, x, y);
 
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT)
+    {
+      rtx result = emit_move_via_integer (mode, x, y, true);
+
+      /* If we can't find an integer mode, use multi words.  */
+      if (result)
+       return result;
+      else
+       return emit_move_multi_word (mode, x, y);
+    }
+
   if (GET_MODE_CLASS (mode) == MODE_CC)
     return emit_move_ccmode (mode, x, y);
 
@@ -3119,7 +3151,7 @@ emit_move_insn_1 (rtx x, rtx y)
      fits within a HOST_WIDE_INT.  */
   if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      rtx ret = emit_move_via_integer (mode, x, y);
+      rtx ret = emit_move_via_integer (mode, x, y, false);
       if (ret)
        return ret;
     }
@@ -3615,7 +3647,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
        offset = 0;
 
       /* Now NOT_STACK gets the number of words that we don't need to
-        allocate on the stack. Convert OFFSET to words too. */
+        allocate on the stack.  Convert OFFSET to words too.  */
       not_stack = (partial - offset) / UNITS_PER_WORD;
       offset /= UNITS_PER_WORD;
 
@@ -3894,7 +3926,7 @@ expand_assignment (tree to, tree from)
 
   if (TREE_CODE (to) == ERROR_MARK)
     {
-      result = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      result = expand_normal (from);
       return;
     }
 
@@ -3920,14 +3952,22 @@ expand_assignment (tree to, tree from)
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
-      to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
+      to_rtx = expand_normal (tem);
 
       if (offset != 0)
        {
-         rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+         rtx offset_rtx;
 
-         gcc_assert (MEM_P (to_rtx));
+         if (!MEM_P (to_rtx))
+           {
+             /* We can get constant negative offsets into arrays with broken
+                user code.  Translate this to a trap instead of ICEing.  */
+             gcc_assert (TREE_CODE (offset) == INTEGER_CST);
+             expand_builtin_trap ();
+             to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+           }
 
+         offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
            offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
@@ -4020,7 +4060,7 @@ expand_assignment (tree to, tree from)
       rtx value;
 
       push_temp_slots ();
-      value = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      value = expand_normal (from);
       if (to_rtx == 0)
        to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
@@ -4081,7 +4121,7 @@ expand_assignment (tree to, tree from)
 
       push_temp_slots ();
       size = expr_size (from);
-      from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      from_rtx = expand_normal (from);
 
       emit_library_call (memmove_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
@@ -4504,7 +4544,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
              /* And now we have to find out if the element itself is fully
                 constructed.  E.g. for union { struct { int a, b; } s; } u
                 = { .s = { .a = 1 } }.  */
-             if (elt_count == count_type_elements (init_sub_type))
+             if (elt_count == count_type_elements (init_sub_type, false))
                clear_this = false;
            }
        }
@@ -4532,10 +4572,11 @@ categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
 }
 
 /* Count the number of scalars in TYPE.  Return -1 on overflow or
-   variable-sized.  */
+   variable-sized.  If ALLOW_FLEXARR is true, don't count flexible
+   array member at the end of the structure.  */
 
 HOST_WIDE_INT
-count_type_elements (tree type)
+count_type_elements (tree type, bool allow_flexarr)
 {
   const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
   switch (TREE_CODE (type))
@@ -4546,7 +4587,7 @@ count_type_elements (tree type)
        if (telts && host_integerp (telts, 1))
          {
            HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
-           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
+           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
            if (n == 0)
              return 0;
            else if (max / n > m)
@@ -4563,9 +4604,23 @@ count_type_elements (tree type)
        for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
          if (TREE_CODE (f) == FIELD_DECL)
            {
-             t = count_type_elements (TREE_TYPE (f));
+             t = count_type_elements (TREE_TYPE (f), false);
              if (t < 0)
-               return -1;
+               {
+                 /* Check for structures with flexible array member.  */
+                 tree tf = TREE_TYPE (f);
+                 if (allow_flexarr
+                     && TREE_CHAIN (f) == NULL
+                     && TREE_CODE (tf) == ARRAY_TYPE
+                     && TYPE_DOMAIN (tf)
+                     && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
+                     && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
+                     && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
+                     && int_size_in_bytes (type) >= 0)
+                   break;
+
+                 return -1;
+               }
              n += t;
            }
 
@@ -4593,7 +4648,6 @@ count_type_elements (tree type)
     case REAL_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
     case POINTER_TYPE:
     case OFFSET_TYPE:
     case REFERENCE_TYPE:
@@ -4623,13 +4677,31 @@ mostly_zeros_p (tree exp)
       if (must_clear)
        return 1;
 
-      elts = count_type_elements (TREE_TYPE (exp));
+      elts = count_type_elements (TREE_TYPE (exp), false);
 
       return nz_elts < elts / 4;
     }
 
   return initializer_zerop (exp);
 }
+
+/* Return 1 if EXP contains all zeros.  */
+
+static int
+all_zeros_p (tree exp)
+{
+  if (TREE_CODE (exp) == CONSTRUCTOR)
+
+    {
+      HOST_WIDE_INT nz_elts, nc_elts, count;
+      bool must_clear;
+
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      return nz_elts == 0;
+    }
+
+  return initializer_zerop (exp);
+}
 \f
 /* Helper function for store_constructor.
    TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
@@ -4795,7 +4867,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                                    make_tree (TREE_TYPE (exp),
                                                               target));
 
-               offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+               offset_rtx = expand_normal (offset);
                gcc_assert (MEM_P (to_rtx));
                
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -5018,7 +5090,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    rtx loop_end = gen_label_rtx ();
                    tree exit_cond;
                    
-                   expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+                   expand_normal (hi_index);
                    unsignedp = TYPE_UNSIGNED (domain);
                    
                    index = build_decl (VAR_DECL, NULL_TREE, domain);
@@ -5042,7 +5114,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                           convert (ssizetype,
                                                    TYPE_SIZE_UNIT (elttype)));
                    
-                   pos_rtx = expand_expr (position, 0, VOIDmode, 0);
+                   pos_rtx = expand_normal (position);
                    xtarget = offset_address (target, pos_rtx,
                                              highest_pow2_factor (position));
                    xtarget = adjust_address (xtarget, mode, 0);
@@ -5088,7 +5160,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                       convert (ssizetype,
                                                TYPE_SIZE_UNIT (elttype)));
                xtarget = offset_address (target,
-                                         expand_expr (position, 0, VOIDmode, 0),
+                                         expand_normal (position),
                                          highest_pow2_factor (position));
                xtarget = adjust_address (xtarget, mode, 0);
                store_expr (value, xtarget, 0);
@@ -5214,7 +5286,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                   vectors in the case of BLKmode vectors.  */
                gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE);
                RTVEC_ELT (vector, eltpos)
-                 = expand_expr (value, NULL_RTX, VOIDmode, 0);
+                 = expand_normal (value);
              }
            else
              {
@@ -5352,7 +5424,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
            }
        }
 
-      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+      temp = expand_normal (exp);
 
       /* If BITSIZE is narrower than the size of the type of EXP
         we will be narrowing TEMP.  Normally, what's wanted are the
@@ -5746,15 +5818,6 @@ force_operand (rtx value, rtx target)
       return subtarget;
     }
 
-  if (code == ZERO_EXTEND || code == SIGN_EXTEND)
-    {
-      if (!target)
-       target = gen_reg_rtx (GET_MODE (value));
-      convert_move (target, force_operand (XEXP (value, 0), NULL),
-                   code == ZERO_EXTEND);
-      return target;
-    }
-
   if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
@@ -5826,8 +5889,30 @@ force_operand (rtx value, rtx target)
     }
   if (UNARY_P (value))
     {
+      if (!target)
+       target = gen_reg_rtx (GET_MODE (value));
       op1 = force_operand (XEXP (value, 0), NULL_RTX);
-      return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+      switch (code)
+       {
+       case ZERO_EXTEND:
+       case SIGN_EXTEND:
+       case TRUNCATE:
+         convert_move (target, op1, code == ZERO_EXTEND);
+         return target;
+
+       case FIX:
+       case UNSIGNED_FIX:
+         expand_fix (target, op1, code == UNSIGNED_FIX);
+         return target;
+
+       case FLOAT:
+       case UNSIGNED_FLOAT:
+         expand_float (target, op1, code == UNSIGNED_FLOAT);
+         return target;
+
+       default:
+         return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+       }
     }
 
 #ifdef INSN_SCHEDULING
@@ -6305,7 +6390,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       result = convert_memory_address (tmode, result);
       tmp = convert_memory_address (tmode, tmp);
 
-      if (modifier == EXPAND_SUM)
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        result = gen_rtx_PLUS (tmode, result, tmp);
       else
        {
@@ -6447,7 +6532,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
      information.  It would be better of the diagnostic routines
      used the file/line information embedded in the tree nodes rather
      than globals.  */
-  if (cfun && EXPR_HAS_LOCATION (exp))
+  if (cfun && cfun->ib_boundaries_block && EXPR_HAS_LOCATION (exp))
     {
       location_t saved_location = input_location;
       input_location = EXPR_LOCATION (exp);
@@ -6502,7 +6587,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   optab this_optab;
   rtx subtarget, original_target;
   int ignore;
-  tree context;
+  tree context, subexp0, subexp1;
   bool reduce_bit_field = false;
 #define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore              \
                                 ? reduce_to_bit_field_precision ((expr), \
@@ -6688,7 +6773,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
          pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
-                               (TREE_CODE (exp) == RESULT_DECL ? 1 : 0));
+                               (TREE_CODE (exp) == RESULT_DECL
+                                || TREE_CODE (exp) == PARM_DECL) ? 1 : 0);
          gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode);
 
          temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
@@ -6828,6 +6914,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return const0_rtx;
        }
 
+      /* Try to avoid creating a temporary at all.  This is possible
+        if all of the initializer is zero.
+        FIXME: try to handle all [0..255] initializers we can handle
+        with memset.  */
+      else if (TREE_STATIC (exp)
+              && !TREE_ADDRESSABLE (exp)
+              && target != 0 && mode == BLKmode
+              && all_zeros_p (exp))
+       {
+         clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
+         return target;
+       }
+
       /* All elts simple constants => refer to a constant in memory.  But
         if this is a non-BLKmode mode, let it store a field at a time
         since that should make a CONST_INT or CONST_DOUBLE when we
@@ -6920,7 +7019,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            int icode;
            rtx reg, insn;
 
-           gcc_assert (modifier == EXPAND_NORMAL);
+           gcc_assert (modifier == EXPAND_NORMAL
+                       || modifier == EXPAND_STACK_PARM);
 
            /* The vectorizer should have already checked the mode.  */
            icode = movmisalign_optab->handlers[mode].insn_code;
@@ -7026,17 +7126,36 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          break;
                        }
                  }
-               else if (TREE_CODE (init) == STRING_CST
-                        && 0 > compare_tree_int (index,
-                                                 TREE_STRING_LENGTH (init)))
+               else if(TREE_CODE (init) == STRING_CST)
                  {
-                   tree type = TREE_TYPE (TREE_TYPE (init));
-                   enum machine_mode mode = TYPE_MODE (type);
-
-                   if (GET_MODE_CLASS (mode) == MODE_INT
-                       && GET_MODE_SIZE (mode) == 1)
-                     return gen_int_mode (TREE_STRING_POINTER (init)
-                                          [TREE_INT_CST_LOW (index)], mode);
+                   tree index1 = index;
+                   tree low_bound = array_ref_low_bound (exp);
+                   index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
+                   
+                   /* Optimize the special-case of a zero lower bound.
+                   
+                      We convert the low_bound to sizetype to avoid some problems
+                      with constant folding.  (E.g. suppose the lower bound is 1,
+                      and its mode is QI.  Without the conversion,l (ARRAY
+                      +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+                      +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
+                   
+                   if (! integer_zerop (low_bound))
+                     index1 = size_diffop (index1, fold_convert (sizetype,
+                                                                 low_bound));
+                 
+                   if (0 > compare_tree_int (index1,
+                                             TREE_STRING_LENGTH (init)))
+                     {
+                       tree type = TREE_TYPE (TREE_TYPE (init));
+                       enum machine_mode mode = TYPE_MODE (type);
+
+                       if (GET_MODE_CLASS (mode) == MODE_INT
+                           && GET_MODE_SIZE (mode) == 1)
+                         return gen_int_mode (TREE_STRING_POINTER (init)
+                                              [TREE_INT_CST_LOW (index1)],
+                                              mode);
+                     }
                  }
              }
          }
@@ -7132,25 +7251,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                          || modifier == EXPAND_STACK_PARM)
                         ? modifier : EXPAND_NORMAL);
 
-       /* If this is a constant, put it into a register if it is a
-          legitimate constant and OFFSET is 0 and memory if it isn't.  */
+       /* If this is a constant, put it into a register if it is a legitimate
+          constant, OFFSET is 0, and we won't try to extract outside the
+          register (in case we were passed a partially uninitialized object
+          or a view_conversion to a larger size).  Force the constant to
+          memory otherwise.  */
        if (CONSTANT_P (op0))
          {
            enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
            if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0)
+               && offset == 0
+               && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
              op0 = force_reg (mode, op0);
            else
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       /* Otherwise, if this object not in memory and we either have an
-          offset or a BLKmode result, put it there.  This case can't occur in
-          C, but can in Ada if we have unchecked conversion of an expression
-          from a scalar type to an array or record type or for an
-          ARRAY_RANGE_REF whose type is BLKmode.  */
+       /* Otherwise, if this object not in memory and we either have an
+          offset, a BLKmode result, or a reference outside the object, put it
+          there.  Such cases can occur in Ada if we have unchecked conversion
+          of an expression from a scalar type to an array or record type or
+          for an ARRAY_RANGE_REF whose type is BLKmode.  */
        else if (!MEM_P (op0)
                 && (offset != 0
+                    || (bitpos + bitsize > GET_MODE_BITSIZE (GET_MODE (op0)))
                     || (code == ARRAY_RANGE_REF && mode == BLKmode)))
          {
            tree nt = build_qualified_type (TREE_TYPE (tem),
@@ -7490,18 +7614,27 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case VIEW_CONVERT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
 
-      /* If the input and output modes are both the same, we are done.
-        Otherwise, if neither mode is BLKmode and both are integral and within
-        a word, we can use gen_lowpart.  If neither is true, make sure the
-        operand is in memory and convert the MEM to the new mode.  */
+      /* If the input and output modes are both the same, we are done.  */
       if (TYPE_MODE (type) == GET_MODE (op0))
        ;
+      /* If neither mode is BLKmode, and both modes are the same size
+        then we can use gen_lowpart.  */
       else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
-              && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-              && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
-              && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
-              && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
-       op0 = gen_lowpart (TYPE_MODE (type), op0);
+              && GET_MODE_SIZE (TYPE_MODE (type))
+                  == GET_MODE_SIZE (GET_MODE (op0)))
+       {
+         if (GET_CODE (op0) == SUBREG)
+           op0 = force_reg (GET_MODE (op0), op0);
+         op0 = gen_lowpart (TYPE_MODE (type), op0);
+       }
+      /* If both modes are integral, then we can convert from one to the
+        other.  */
+      else if (SCALAR_INT_MODE_P (GET_MODE (op0))
+              && SCALAR_INT_MODE_P (TYPE_MODE (type)))
+       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0, 
+                            TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+      /* As a last resort, spill op0 to memory, and reload it in a 
+        different mode.  */
       else if (!MEM_P (op0))
        {
          /* If the operand is not a MEM, force it into memory.  Since we
@@ -7622,7 +7755,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            }
 
          else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
                   && TREE_CONSTANT (TREE_OPERAND (exp, 0)))
            {
              rtx constant_part;
@@ -7755,7 +7888,43 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         from a narrower type.  If this machine supports multiplying
         in that narrower type with a result in the desired type,
         do it that way, and avoid the explicit type-conversion.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+
+      subexp0 = TREE_OPERAND (exp, 0);
+      subexp1 = TREE_OPERAND (exp, 1);
+      /* First, check if we have a multiplication of one signed and one
+        unsigned operand.  */
+      if (TREE_CODE (subexp0) == NOP_EXPR
+         && TREE_CODE (subexp1) == NOP_EXPR
+         && TREE_CODE (type) == INTEGER_TYPE
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
+         && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
+         && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+             != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+       {
+         enum machine_mode innermode
+           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+         this_optab = usmul_widen_optab;
+         if (mode == GET_MODE_WIDER_MODE (innermode))
+           {
+             if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+               {
+                 if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op0, &op1, 0);
+                 else
+                   expand_operands (TREE_OPERAND (subexp0, 0),
+                                    TREE_OPERAND (subexp1, 0),
+                                    NULL_RTX, &op1, &op0, 0);
+
+                 goto binop3;
+               }
+           }
+       }
+      /* Check for a multiplication with matching signedness.  */
+      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
          && TREE_CODE (type) == INTEGER_TYPE
          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
@@ -7794,27 +7963,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (exp, 1),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  else
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                    NULL_RTX, &op0, &op1, 0);
+                                    NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  goto binop3;
                }
              else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
                  rtx htem, hipart;
-                 op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    NULL_RTX, VOIDmode, 0);
+                 op0 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    op1 = convert_modes (innermode, mode,
-                                        expand_expr (TREE_OPERAND (exp, 1),
-                                                     NULL_RTX, VOIDmode, 0),
+                                        expand_normal (TREE_OPERAND (exp, 1)),
                                         unsignedp);
                  else
-                   op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                      NULL_RTX, VOIDmode, 0);
+                   op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
                  hipart = gen_highpart (innermode, temp);
@@ -7864,14 +8030,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       gcc_unreachable ();                      /* Not used for C.  */
 
     case FIX_TRUNC_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       expand_fix (target, op0, unsignedp);
       return target;
 
     case FLOAT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
        target = gen_reg_rtx (mode);
       /* expand_float can't figure out what to do if FROM has VOIDmode.
@@ -7951,69 +8117,76 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (! CONSTANT_P (op1))
        op1 = force_reg (mode, op1);
 
-#ifdef HAVE_conditional_move
-      /* Use a conditional move if possible.  */
-      if (can_conditionally_move_p (mode))
-       {
-         enum rtx_code comparison_code;
-         rtx insn;
+      {
+       enum rtx_code comparison_code;
+       rtx cmpop1 = op1;
 
-         if (code == MAX_EXPR)
-           comparison_code = unsignedp ? GEU : GE;
-         else
-           comparison_code = unsignedp ? LEU : LE;
+       if (code == MAX_EXPR)
+         comparison_code = unsignedp ? GEU : GE;
+       else
+         comparison_code = unsignedp ? LEU : LE;
 
-         /* ??? Same problem as in expmed.c: emit_conditional_move
-            forces a stack adjustment via compare_from_rtx, and we
-            lose the stack adjustment if the sequence we are about
-            to create is discarded.  */
-         do_pending_stack_adjust ();
+       /* Canonicalize to comparisons against 0.  */
+       if (op1 == const1_rtx)
+         {
+           /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1)
+              or (a != 0 ? a : 1) for unsigned.
+              For MIN we are safe converting (a <= 1 ? a : 1)
+              into (a <= 0 ? a : 1)  */
+           cmpop1 = const0_rtx;
+           if (code == MAX_EXPR)
+             comparison_code = unsignedp ? NE : GT;
+         }
+       if (op1 == constm1_rtx && !unsignedp)
+         {
+           /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1)
+              and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */
+           cmpop1 = const0_rtx;
+           if (code == MIN_EXPR)
+             comparison_code = LT;
+         }
+#ifdef HAVE_conditional_move
+       /* Use a conditional move if possible.  */
+       if (can_conditionally_move_p (mode))
+         {
+           rtx insn;
 
-         start_sequence ();
+           /* ??? Same problem as in expmed.c: emit_conditional_move
+              forces a stack adjustment via compare_from_rtx, and we
+              lose the stack adjustment if the sequence we are about
+              to create is discarded.  */
+           do_pending_stack_adjust ();
 
-         /* Try to emit the conditional move.  */
-         insn = emit_conditional_move (target, comparison_code,
-                                       op0, op1, mode,
-                                       op0, op1, mode,
-                                       unsignedp);
+           start_sequence ();
 
-         /* If we could do the conditional move, emit the sequence,
-            and return.  */
-         if (insn)
-           {
-             rtx seq = get_insns ();
-             end_sequence ();
-             emit_insn (seq);
-             return target;
-           }
+           /* Try to emit the conditional move.  */
+           insn = emit_conditional_move (target, comparison_code,
+                                         op0, cmpop1, mode,
+                                         op0, op1, mode,
+                                         unsignedp);
 
-         /* Otherwise discard the sequence and fall back to code with
-            branches.  */
-         end_sequence ();
-       }
-#endif
-      if (target != op0)
-       emit_move_insn (target, op0);
+           /* If we could do the conditional move, emit the sequence,
+              and return.  */
+           if (insn)
+             {
+               rtx seq = get_insns ();
+               end_sequence ();
+               emit_insn (seq);
+               return target;
+             }
 
-      temp = gen_label_rtx ();
+           /* Otherwise discard the sequence and fall back to code with
+              branches.  */
+           end_sequence ();
+         }
+#endif
+       if (target != op0)
+         emit_move_insn (target, op0);
 
-      /* If this mode is an integer too wide to compare properly,
-        compare word by word.  Rely on cse to optimize constant cases.  */
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && ! can_compare_p (GE, mode, ccp_jump))
-       {
-         if (code == MAX_EXPR)
-           do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
-                                         NULL_RTX, temp);
-         else
-           do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
-                                         NULL_RTX, temp);
-       }
-      else
-       {
-         do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX, temp);
-       }
+       temp = gen_label_rtx ();
+       do_compare_rtx_and_jump (target, cmpop1, comparison_code,
+                                unsignedp, mode, NULL_RTX, NULL_RTX, temp);
+      }
       emit_move_insn (target, op1);
       emit_label (temp);
       return target;
@@ -8284,8 +8457,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case COMPLEX_EXPR:
       /* Get the rtx code of the operands.  */
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      op1 = expand_normal (TREE_OPERAND (exp, 1));
 
       if (!target)
        target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
@@ -8297,11 +8470,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return target;
 
     case REALPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, false);
 
     case IMAGPART_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
       return read_complex_part (op0, true);
 
     case RESX_EXPR:
@@ -8372,19 +8545,44 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         rtx op2;
 
         this_optab = optab_for_tree_code (code, type);
-        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
-        op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+        op2 = expand_normal (oprnd2);
         temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
                                  target, unsignedp);
         gcc_assert (temp);
         return temp;
       }
 
+    case DOT_PROD_EXPR:
+      {
+       tree oprnd0 = TREE_OPERAND (exp, 0);
+       tree oprnd1 = TREE_OPERAND (exp, 1);
+       tree oprnd2 = TREE_OPERAND (exp, 2);
+       rtx op2;
+
+       expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+       op2 = expand_normal (oprnd2);
+       target = expand_widen_pattern_expr (exp, op0, op1, op2, 
+                                           target, unsignedp);
+       return target;
+      }
+
+    case WIDEN_SUM_EXPR:
+      {
+        tree oprnd0 = TREE_OPERAND (exp, 0);
+        tree oprnd1 = TREE_OPERAND (exp, 1);
+                                                                               
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+        target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
+                                            target, unsignedp);
+        return target;
+      }
+
     case REDUC_MAX_EXPR:
     case REDUC_MIN_EXPR:
     case REDUC_PLUS_EXPR:
       {
-        op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+        op0 = expand_normal (TREE_OPERAND (exp, 0));
         this_optab = optab_for_tree_code (code, type);
         temp = expand_unop (mode, this_optab, op0, target, unsignedp);
         gcc_assert (temp);
@@ -8879,13 +9077,13 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
   if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
     {
       enum machine_mode omode = TYPE_MODE (index_type);
-      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+      rtx rangertx = expand_normal (range);
 
       /* We must handle the endpoints in the original mode.  */
       index_expr = build2 (MINUS_EXPR, index_type,
                           index_expr, minval);
       minval = integer_zero_node;
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      index = expand_normal (index_expr);
       emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
                               omode, 1, default_label);
       /* Now we can safely truncate.  */
@@ -8900,7 +9098,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
          index_type = TREE_TYPE (index_expr);
        }
 
-      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      index = expand_normal (index_expr);
     }
 
   do_pending_stack_adjust ();
@@ -8910,7 +9108,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (index, op_mode))
     index = copy_to_mode_reg (op_mode, index);
 
-  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+  op1 = expand_normal (minval);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
   op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
@@ -8919,7 +9117,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       (op1, op_mode))
     op1 = copy_to_mode_reg (op_mode, op1);
 
-  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+  op2 = expand_normal (range);
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
   op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
@@ -9025,14 +9223,13 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
   index_expr = fold_build2 (MINUS_EXPR, index_type,
                            convert (index_type, index_expr),
                            convert (index_type, minval));
-  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  index = expand_normal (index_expr);
   do_pending_stack_adjust ();
 
   do_tablejump (index, TYPE_MODE (index_type),
                convert_modes (TYPE_MODE (index_type),
                               TYPE_MODE (TREE_TYPE (range)),
-                              expand_expr (range, NULL_RTX,
-                                           VOIDmode, 0),
+                              expand_normal (range),
                               TYPE_UNSIGNED (TREE_TYPE (range))),
                table_label, default_label);
   return 1;