]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/expr.c
* expr.c (move_block_from_reg): Try using an integral mov operation first.
[gcc.git] / gcc / expr.c
index 5dc9bcd828e9ec3d06344713e010cd0696c14f4c..7a855ad1475f00fa194e984f66e6196febf4a010 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
 
 This file is part of GNU CC.
 
@@ -177,6 +177,7 @@ static tree save_noncopied_parts PROTO((tree, tree));
 static tree init_noncopied_parts PROTO((tree, tree));
 static int safe_from_p         PROTO((rtx, tree));
 static int fixed_type_p                PROTO((tree));
 static tree init_noncopied_parts PROTO((tree, tree));
 static int safe_from_p         PROTO((rtx, tree));
 static int fixed_type_p                PROTO((tree));
+static rtx var_rtx             PROTO((tree));
 static int get_pointer_alignment PROTO((tree, unsigned));
 static tree string_constant    PROTO((tree, tree *));
 static tree c_strlen           PROTO((tree));
 static int get_pointer_alignment PROTO((tree, unsigned));
 static tree string_constant    PROTO((tree, tree *));
 static tree c_strlen           PROTO((tree));
@@ -611,115 +612,17 @@ convert_move (to, from, unsignedp)
     {
       rtx value;
 
     {
       rtx value;
 
-#ifdef HAVE_extendqfhf2
-      if (HAVE_extendqfhf2 && from_mode == QFmode && to_mode == HFmode)
+      if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
        {
        {
-         emit_unop_insn (CODE_FOR_extendqfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfsf2
-      if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfdf2
-      if (HAVE_extendqfdf2 && from_mode == QFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfxf2
-      if (HAVE_extendqfxf2 && from_mode == QFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqftf2
-      if (HAVE_extendqftf2 && from_mode == QFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendhftqf2
-      if (HAVE_extendhftqf2 && from_mode == HFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendhfsf2
-      if (HAVE_extendhfsf2 && from_mode == HFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhfdf2
-      if (HAVE_extendhfdf2 && from_mode == HFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhfxf2
-      if (HAVE_extendhfxf2 && from_mode == HFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhftf2
-      if (HAVE_extendhftf2 && from_mode == HFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendsfdf2
-      if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendsfxf2
-      if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendsftf2
-      if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extenddfxf2
-      if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extenddftf2
-      if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
-         return;
+         /* Try converting directly if the insn is supported.  */
+         if ((code = can_extend_p (to_mode, from_mode, 0))
+             != CODE_FOR_nothing)
+           {
+             emit_unop_insn (code, to, from, UNKNOWN);
+             return;
+           }
        }
        }
-#endif
-
 #ifdef HAVE_trunchfqf2
       if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
        {
 #ifdef HAVE_trunchfqf2
       if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
        {
@@ -791,6 +694,36 @@ convert_move (to, from, unsignedp)
          return;
        }
 #endif
          return;
        }
 #endif
+
+#ifdef HAVE_truncsftqf2
+      if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_truncdftqf2
+      if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_truncxftqf2
+      if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_trunctftqf2
+      if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+
 #ifdef HAVE_truncdfsf2
       if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
        {
 #ifdef HAVE_truncdfsf2
       if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
        {
@@ -1359,7 +1292,20 @@ convert_modes (mode, oldmode, x, unsignedp)
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
-    return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
+    {
+      HOST_WIDE_INT val = INTVAL (x);
+
+      if (oldmode != VOIDmode
+         && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
+       {
+         int width = GET_MODE_BITSIZE (oldmode);
+
+         /* We need to zero extend VAL.  */
+         val &= ((HOST_WIDE_INT) 1 << width) - 1;
+       }
+
+      return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+    }
 
   /* We can do this with a gen_lowpart if both desired and current modes
      are integer, and this is either a constant integer, a register, or a
 
   /* We can do this with a gen_lowpart if both desired and current modes
      are integer, and this is either a constant integer, a register, or a
@@ -1517,7 +1463,7 @@ move_by_pieces (to, from, len, align)
     }
 
   /* The code above should have handled everything.  */
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data.len > 0)
     abort ();
 }
 
     abort ();
 }
 
@@ -1771,9 +1717,21 @@ move_block_from_reg (regno, x, nregs, size)
 {
   int i;
   rtx pat, last;
 {
   int i;
   rtx pat, last;
+  enum machine_mode mode;
 
 
+  /* If SIZE is that of a mode no bigger than a word, just use that
+     mode's store operation.  */
+  if (size <= UNITS_PER_WORD
+      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+    {
+      emit_move_insn (change_address (x, mode, NULL),
+                     gen_rtx (REG, mode, regno));
+      return;
+    }
+    
   /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
   /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
-     to the left before storing to memory.  */
+     to the left before storing to memory.  Note that the previous test
+     doesn't handle all cases (e.g. SIZE == 3).  */
   if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
     {
       rtx tem = operand_subword (x, 0, 1, BLKmode);
   if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
     {
       rtx tem = operand_subword (x, 0, 1, BLKmode);
@@ -1852,9 +1810,15 @@ emit_group_load (x, y)
        {
          if (GET_MODE (target_reg) == GET_MODE (y))
            source = y;
        {
          if (GET_MODE (target_reg) == GET_MODE (y))
            source = y;
-         else if (GET_MODE_SIZE (GET_MODE (target_reg))
-                  == GET_MODE_SIZE (GET_MODE (y)))
-           source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0);
+         /* Allow for the target_reg to be smaller than the input register
+            to allow for AIX with 4 DF arguments after a single SI arg.  The
+            last DF argument will only load 1 word into the integer registers,
+            but load a DF value into the float registers.  */
+         else if ((GET_MODE_SIZE (GET_MODE (target_reg))
+                   <= GET_MODE_SIZE (GET_MODE (y)))
+                  && GET_MODE (target_reg) == word_mode)
+           /* This might be a const_double, so we can't just use SUBREG.  */
+           source = operand_subword (y, 0, 0, VOIDmode);
          else
            abort ();       
        }
          else
            abort ();       
        }
@@ -1896,7 +1860,11 @@ emit_group_store (x, y)
                                 plus_constant (XEXP (x, 0),
                                                INTVAL (XEXP (element, 1))));
       else if (XEXP (element, 1) == const0_rtx)
                                 plus_constant (XEXP (x, 0),
                                                INTVAL (XEXP (element, 1))));
       else if (XEXP (element, 1) == const0_rtx)
-       target = x;
+       {
+         target = x;
+         if (GET_MODE (target) != GET_MODE (source_reg))
+           target = gen_lowpart (GET_MODE (source_reg), target);
+       }
       else
        abort ();
 
       else
        abort ();
 
@@ -2458,12 +2426,6 @@ 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);
 
      Default is below for small data on big-endian machines; else above.  */
   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
 
-  /* If we're placing part of X into a register and part of X onto
-     the stack, indicate that the entire register is clobbered to
-     keep flow from thinking the unused part of the register is live.  */
-  if (partial > 0 && reg != 0)
-    emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
-
   /* Invert direction if stack is post-update.  */
   if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
   /* Invert direction if stack is post-update.  */
   if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
@@ -2837,8 +2799,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       int alignment;
 
       push_temp_slots ();
       int alignment;
 
       push_temp_slots ();
-      tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
-                                     &mode1, &unsignedp, &volatilep);
+      tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
+                                &unsignedp, &volatilep, &alignment);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
@@ -2846,7 +2808,6 @@ expand_assignment (to, from, want_value, suggest_reg)
       if (mode1 == VOIDmode && want_value)
        tem = stabilize_reference (tem);
 
       if (mode1 == VOIDmode && want_value)
        tem = stabilize_reference (tem);
 
-      alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
       to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
       if (offset != 0)
        {
       to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
       if (offset != 0)
        {
@@ -2857,14 +2818,6 @@ expand_assignment (to, from, want_value, suggest_reg)
          to_rtx = change_address (to_rtx, VOIDmode,
                                   gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
                                            force_reg (ptr_mode, offset_rtx)));
          to_rtx = change_address (to_rtx, VOIDmode,
                                   gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
                                            force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            align of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (to) == COMPONENT_REF
-             || TREE_CODE (to) == BIT_FIELD_REF)
-           alignment
-             = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
        }
       if (volatilep)
        {
        }
       if (volatilep)
        {
@@ -3056,6 +3009,17 @@ store_expr (exp, target, want_value)
         For non-BLKmode, it is more efficient not to do this.  */
 
       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
         For non-BLKmode, it is more efficient not to do this.  */
 
       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+      rtx flag = NULL_RTX;
+      tree left_cleanups = NULL_TREE;
+      tree right_cleanups = NULL_TREE;
+      tree old_cleanups = cleanups_this_call;
+
+      /* Used to save a pointer to the place to put the setting of
+        the flag that indicates if this side of the conditional was
+        taken.  We backpatch the code, if we find out later that we
+        have any conditional cleanups that need to be performed.  */
+      rtx dest_right_flag = NULL_RTX;
+      rtx dest_left_flag = NULL_RTX;
 
       emit_queue ();
       target = protect_from_queue (target, 1);
 
       emit_queue ();
       target = protect_from_queue (target, 1);
@@ -3064,14 +3028,74 @@ store_expr (exp, target, want_value)
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
       store_expr (TREE_OPERAND (exp, 1), target, 0);
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
       store_expr (TREE_OPERAND (exp, 1), target, 0);
+      dest_left_flag = get_last_insn ();
+      /* Handle conditional cleanups, if any.  */
+      left_cleanups = defer_cleanups_to (old_cleanups);
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
       store_expr (TREE_OPERAND (exp, 2), target, 0);
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
       store_expr (TREE_OPERAND (exp, 2), target, 0);
+      dest_right_flag = get_last_insn ();
+      /* Handle conditional cleanups, if any.  */
+      right_cleanups = defer_cleanups_to (old_cleanups);
       emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
       emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
+
+      /* Add back in any conditional cleanups.  */
+      if (left_cleanups || right_cleanups)
+       {
+         tree new_cleanups;
+         tree cond;
+         rtx last;
+
+         /* Now that we know that a flag is needed, go back and add in the
+            setting of the flag.  */
+
+         flag = gen_reg_rtx (word_mode);
+
+         /* Do the left side flag.  */
+         last = get_last_insn ();
+         /* Flag left cleanups as needed.  */
+         emit_move_insn (flag, const1_rtx);
+         /* ??? deprecated, use sequences instead.  */
+         reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
+
+         /* Do the right side flag.  */
+         last = get_last_insn ();
+         /* Flag left cleanups as needed.  */
+         emit_move_insn (flag, const0_rtx);
+         /* ??? deprecated, use sequences instead.  */
+         reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
+
+         /* All cleanups must be on the function_obstack.  */
+         push_obstacks_nochange ();
+         resume_temporary_allocation ();
+
+         /* convert flag, which is an rtx, into a tree.  */
+         cond = make_node (RTL_EXPR);
+         TREE_TYPE (cond) = integer_type_node;
+         RTL_EXPR_RTL (cond) = flag;
+         RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+         cond = save_expr (cond);
+
+         if (! left_cleanups)
+           left_cleanups = integer_zero_node;
+         if (! right_cleanups)
+           right_cleanups = integer_zero_node;
+         new_cleanups = build (COND_EXPR, void_type_node,
+                               truthvalue_conversion (cond),
+                               left_cleanups, right_cleanups);
+         new_cleanups = fold (new_cleanups);
+
+         pop_obstacks ();
+
+         /* Now add in the conditionalized cleanups.  */
+         cleanups_this_call
+           = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+         expand_eh_region_start ();
+       }
       return want_value ? target : NULL_RTX;
     }
   else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
       return want_value ? target : NULL_RTX;
     }
   else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
@@ -3117,8 +3141,11 @@ store_expr (exp, target, want_value)
       /* 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
       /* 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
-        the extend.  */
-      if (! want_value)
+        the extend.  But don't do this if the type of EXP is a subtype
+        of something else since then the conversion might involve
+        more than just converting modes.  */
+      if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+         && TREE_TYPE (TREE_TYPE (exp)) == 0)
        {
          if (TREE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
        {
          if (TREE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
@@ -3267,7 +3294,7 @@ store_expr (exp, target, want_value)
                {
 #ifdef TARGET_MEM_FUNCTIONS
                  emit_library_call (memset_libfunc, 0, VOIDmode, 3,
                {
 #ifdef TARGET_MEM_FUNCTIONS
                  emit_library_call (memset_libfunc, 0, VOIDmode, 3,
-                                    addr, Pmode,
+                                    addr, ptr_mode,
                                     const0_rtx, TYPE_MODE (integer_type_node),
                                     convert_to_mode (TYPE_MODE (sizetype),
                                                      size,
                                     const0_rtx, TYPE_MODE (integer_type_node),
                                     convert_to_mode (TYPE_MODE (sizetype),
                                                      size,
@@ -3275,7 +3302,7 @@ store_expr (exp, target, want_value)
                                     TYPE_MODE (sizetype));
 #else
                  emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
                                     TYPE_MODE (sizetype));
 #else
                  emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
-                                    addr, Pmode,
+                                    addr, ptr_mode,
                                     convert_to_mode (TYPE_MODE (integer_type_node),
                                                      size,
                                                      TREE_UNSIGNED (integer_type_node)),
                                     convert_to_mode (TYPE_MODE (integer_type_node),
                                                      size,
                                                      TREE_UNSIGNED (integer_type_node)),
@@ -3588,7 +3615,7 @@ store_constructor (exp, target, cleared)
             It is also needed to check for missing elements.  */
          for (elt = CONSTRUCTOR_ELTS (exp);
               elt != NULL_TREE;
             It is also needed to check for missing elements.  */
          for (elt = CONSTRUCTOR_ELTS (exp);
               elt != NULL_TREE;
-              elt = TREE_CHAIN (elt), i++)
+              elt = TREE_CHAIN (elt))
            {
              tree index = TREE_PURPOSE (elt);
              HOST_WIDE_INT this_node_count;
            {
              tree index = TREE_PURPOSE (elt);
              HOST_WIDE_INT this_node_count;
@@ -4034,6 +4061,18 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
+      /* If BITSIZE is narrower than the size of the type of EXP
+        we will be narrowing TEMP.  Normally, what's wanted are the
+        low-order bits.  However, if EXP's type is a record and this is
+        big-endian machine, we want the upper BITSIZE bits.  */
+      if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
+         && bitsize < GET_MODE_BITSIZE (GET_MODE (temp))
+         && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+       temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
+                            size_int (GET_MODE_BITSIZE (GET_MODE (temp))
+                                      - bitsize),
+                            temp, 1);
+
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
         MODE.  */
       if (mode != VOIDmode && mode != BLKmode
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
         MODE.  */
       if (mode != VOIDmode && mode != BLKmode
@@ -4156,6 +4195,9 @@ get_inner_unaligned_p (exp)
    giving the variable offset (in units) in *POFFSET.
    This offset is in addition to the bit position.
    If the position is not variable, we store 0 in *POFFSET.
    giving the variable offset (in units) in *POFFSET.
    This offset is in addition to the bit position.
    If the position is not variable, we store 0 in *POFFSET.
+   We set *PALIGNMENT to the alignment in bytes of the address that will be
+   computed.  This is the alignment of the thing we return if *POFFSET
+   is zero, but can be more less strictly aligned if *POFFSET is nonzero.
 
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
 
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
@@ -4166,11 +4208,11 @@ get_inner_unaligned_p (exp)
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
-   this case, but the address of the object can be found.  */
+   this case, but the address of the object can be found.   */
 
 tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
 tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
-                    punsignedp, pvolatilep)
+                    punsignedp, pvolatilep, palignment)
      tree exp;
      int *pbitsize;
      int *pbitpos;
      tree exp;
      int *pbitsize;
      int *pbitpos;
@@ -4178,11 +4220,13 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
+     int *palignment;
 {
   tree orig_exp = exp;
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
   tree offset = integer_zero_node;
 {
   tree orig_exp = exp;
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
   tree offset = integer_zero_node;
+  int alignment = BIGGEST_ALIGNMENT;
 
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
 
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
@@ -4268,7 +4312,8 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            }
 
          index = fold (build (MULT_EXPR, index_type, index,
            }
 
          index = fold (build (MULT_EXPR, index_type, index,
-                              TYPE_SIZE (TREE_TYPE (exp))));
+                              convert (index_type,
+                                       TYPE_SIZE (TREE_TYPE (exp)))));
 
          if (TREE_CODE (index) == INTEGER_CST
              && TREE_INT_CST_HIGH (index) == 0)
 
          if (TREE_CODE (index) == INTEGER_CST
              && TREE_INT_CST_HIGH (index) == 0)
@@ -4291,9 +4336,20 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
       /* If any reference in the chain is volatile, the effect is volatile.  */
       if (TREE_THIS_VOLATILE (exp))
        *pvolatilep = 1;
       /* If any reference in the chain is volatile, the effect is volatile.  */
       if (TREE_THIS_VOLATILE (exp))
        *pvolatilep = 1;
+
+      /* If the offset is non-constant already, then we can't assume any
+        alignment more than the alignment here.  */
+      if (! integer_zerop (offset))
+       alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
       exp = TREE_OPERAND (exp, 0);
     }
 
       exp = TREE_OPERAND (exp, 0);
     }
 
+  if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+    alignment = MIN (alignment, DECL_ALIGN (exp));
+  else if (TREE_TYPE (exp) != 0)
+    alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
   if (integer_zerop (offset))
     offset = 0;
 
   if (integer_zerop (offset))
     offset = 0;
 
@@ -4302,6 +4358,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
   *pmode = mode;
   *poffset = offset;
 
   *pmode = mode;
   *poffset = offset;
+  *palignment = alignment / BITS_PER_UNIT;
   return exp;
 }
 \f
   return exp;
 }
 \f
@@ -4620,6 +4677,24 @@ fixed_type_p (exp)
     return 1;
   return 0;
 }
     return 1;
   return 0;
 }
+
+/* Subroutine of expand_expr: return rtx if EXP is a
+   variable or parameter; else return 0.  */
+
+static rtx
+var_rtx (exp)
+     tree exp;
+{
+  STRIP_NOPS (exp);
+  switch (TREE_CODE (exp))
+    {
+    case PARM_DECL:
+    case VAR_DECL:
+      return DECL_RTL (exp);
+    default:
+      return 0;
+    }
+}
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -5033,22 +5108,33 @@ expand_expr (exp, target, tmode, modifier)
         further information, see tree.def.  */
       if (placeholder_list)
        {
         further information, see tree.def.  */
       if (placeholder_list)
        {
-         tree object;
+         tree need_type = TYPE_MAIN_VARIANT (type);
+         tree object = 0;
          tree old_list = placeholder_list;
          tree old_list = placeholder_list;
+         tree elt;
 
 
-         for (object = TREE_PURPOSE (placeholder_list);
-              (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-               != TYPE_MAIN_VARIANT (type))
-              && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
-              object = TREE_OPERAND (object, 0))
-           ;
-
-         if (object != 0
-             && (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-                 == TYPE_MAIN_VARIANT (type)))
+         /* See if the object is the type that we want.  Then see if
+            the operand of any reference is the type we want.  */
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_PURPOSE (placeholder_list)))
+              == need_type))
+           object = TREE_PURPOSE (placeholder_list);
+
+         /* Find the innermost reference that is of the type we want.    */
+         for (elt = TREE_PURPOSE (placeholder_list);
+              elt != 0
+              && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
+              elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+                      || TREE_CODE (elt) == COND_EXPR)
+                     ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
+           if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+               && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
+                   == need_type))
+             object = TREE_OPERAND (elt, 0);
+
+         if (object != 0)
            {
              /* Expand this object skipping the list entries before
                 it was found in case it is also a PLACEHOLDER_EXPR.
            {
              /* Expand this object skipping the list entries before
                 it was found in case it is also a PLACEHOLDER_EXPR.
@@ -5175,7 +5261,10 @@ expand_expr (exp, target, tmode, modifier)
 
       else
        {
 
       else
        {
-         if (target == 0 || ! safe_from_p (target, exp))
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (target == 0 || ! safe_from_p (target, exp)
+             || GET_CODE (target) == PARALLEL)
            {
              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
                target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
            {
              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
                target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
@@ -5398,8 +5487,46 @@ expand_expr (exp, target, tmode, modifier)
 
          for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
               elt = TREE_CHAIN (elt))
 
          for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
               elt = TREE_CHAIN (elt))
-           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
-             return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+               /* We can normally use the value of the field in the
+                  CONSTRUCTOR.  However, if this is a bitfield in
+                  an integral mode that we can fit in a HOST_WIDE_INT,
+                  we must mask only the number of bits in the bitfield,
+                  since this is done implicitly by the constructor.  If
+                  the bitfield does not meet either of those conditions,
+                  we can't do this optimization.  */
+               && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
+                   || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
+                        == MODE_INT)
+                       && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+                           <= HOST_BITS_PER_WIDE_INT))))
+             {
+               op0 =  expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+               if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+                 {
+                   int bitsize = DECL_FIELD_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);
+                     }
+                   else
+                     {
+                       tree count
+                         = build_int_2 (imode - bitsize, 0);
+
+                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                     }
+                 }
+
+               return op0;
+             }
        }
 
       {
        }
 
       {
@@ -5408,9 +5535,10 @@ expand_expr (exp, target, tmode, modifier)
        int bitpos;
        tree offset;
        int volatilep = 0;
        int bitpos;
        tree offset;
        int volatilep = 0;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep);
        int alignment;
        int alignment;
+       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                       &mode1, &unsignedp, &volatilep,
+                                       &alignment);
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
@@ -5441,7 +5569,6 @@ expand_expr (exp, target, tmode, modifier)
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
        if (offset != 0)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
        if (offset != 0)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
@@ -5451,14 +5578,6 @@ expand_expr (exp, target, tmode, modifier)
            op0 = change_address (op0, VOIDmode,
                                  gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
                                           force_reg (ptr_mode, offset_rtx)));
            op0 = change_address (op0, VOIDmode,
                                  gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
                                           force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            size of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (exp) == COMPONENT_REF
-             || TREE_CODE (exp) == BIT_FIELD_REF)
-           alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                        / BITS_PER_UNIT);
          }
 
        /* Don't forget about volatility even if this is a bitfield.  */
          }
 
        /* Don't forget about volatility even if this is a bitfield.  */
@@ -5480,7 +5599,9 @@ expand_expr (exp, target, tmode, modifier)
            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
            || (modifier != EXPAND_CONST_ADDRESS
                && modifier != EXPAND_INITIALIZER
            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
            || (modifier != EXPAND_CONST_ADDRESS
                && modifier != EXPAND_INITIALIZER
-               && ((mode1 != BLKmode && ! direct_load[(int) mode1])
+               && ((mode1 != BLKmode && ! direct_load[(int) mode1]
+                    && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+                    && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
                    /* If the field isn't aligned enough to fetch as a memref,
                       fetch it as a bit field.  */
                    || (SLOW_UNALIGNED_ACCESS
                    /* If the field isn't aligned enough to fetch as a memref,
                       fetch it as a bit field.  */
                    || (SLOW_UNALIGNED_ACCESS
@@ -5524,6 +5645,18 @@ expand_expr (exp, target, tmode, modifier)
                                     unsignedp, target, ext_mode, ext_mode,
                                     alignment,
                                     int_size_in_bytes (TREE_TYPE (tem)));
                                     unsignedp, target, ext_mode, ext_mode,
                                     alignment,
                                     int_size_in_bytes (TREE_TYPE (tem)));
+
+           /* If the result is a record type and BITSIZE is narrower than
+              the mode of OP0, an integral mode, and this is a big endian
+              machine, we must put the field into the high-order bits.  */
+           if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
+               && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+               && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
+             op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+                                 size_int (GET_MODE_BITSIZE (GET_MODE (op0))
+                                           - bitsize),
+                                 op0, 1);
+
            if (mode == BLKmode)
              {
                rtx new = assign_stack_temp (ext_mode,
            if (mode == BLKmode)
              {
                rtx new = assign_stack_temp (ext_mode,
@@ -5557,10 +5690,13 @@ expand_expr (exp, target, tmode, modifier)
 
        MEM_IN_STRUCT_P (op0) = 1;
        MEM_VOLATILE_P (op0) |= volatilep;
 
        MEM_IN_STRUCT_P (op0) = 1;
        MEM_VOLATILE_P (op0) |= volatilep;
-       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
+       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+           || modifier == EXPAND_CONST_ADDRESS
+           || modifier == EXPAND_INITIALIZER)
          return op0;
          return op0;
-       if (target == 0)
+       else if (target == 0)
          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
        convert_move (target, op0, unsignedp);
        return target;
       }
        convert_move (target, op0, unsignedp);
        return target;
       }
@@ -6384,6 +6520,31 @@ expand_expr (exp, target, tmode, modifier)
                          VOIDmode, 0);
 
     case COND_EXPR:
                          VOIDmode, 0);
 
     case COND_EXPR:
+      /* If we would have a "singleton" (see below) were it not for a
+        conversion in each arm, bring that conversion back out.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
+         && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
+         && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
+             == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
+       {
+         tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+         tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+         if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
+              && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
+                 && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+           return expand_expr (build1 (NOP_EXPR, type,
+                                       build (COND_EXPR, TREE_TYPE (true),
+                                              TREE_OPERAND (exp, 0),
+                                              true, false)),
+                               target, tmode, modifier);
+       }
+
       {
        rtx flag = NULL_RTX;
        tree left_cleanups = NULL_TREE;
       {
        rtx flag = NULL_RTX;
        tree left_cleanups = NULL_TREE;
@@ -6431,27 +6592,11 @@ expand_expr (exp, target, tmode, modifier)
            return target;
          }
 
            return target;
          }
 
-       /* If we are not to produce a result, we have no target.  Otherwise,
-          if a target was specified use it; it will not be used as an
-          intermediate target unless it is safe.  If no target, use a 
-          temporary.  */
-
-       if (ignore)
-         temp = 0;
-       else if (original_target
-                && safe_from_p (original_target, TREE_OPERAND (exp, 0))
-                && GET_MODE (original_target) == mode
-                && ! (GET_CODE (original_target) == MEM
-                      && MEM_VOLATILE_P (original_target)))
-         temp = original_target;
-       else
-         temp = assign_temp (type, 0, 0, 1);
-
-       /* Check for X ? A + B : A.  If we have this, we can copy
-          A to the output and conditionally add B.  Similarly for unary
-          operations.  Don't do this if X has side-effects because
-          those side effects might affect A or B and the "?" operation is
-          a sequence point in ANSI.  (We test for side effects later.)  */
+       /* Check for X ? A + B : A.  If we have this, we can copy A to the
+          output and conditionally add B.  Similarly for unary operations.
+          Don't do this if X has side-effects because those side effects
+          might affect A or B and the "?" operation is a sequence point in
+          ANSI.  (operand_equal_p tests for side effects.)  */
 
        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
            && operand_equal_p (TREE_OPERAND (exp, 2),
 
        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
            && operand_equal_p (TREE_OPERAND (exp, 2),
@@ -6470,16 +6615,38 @@ expand_expr (exp, target, tmode, modifier)
                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
          singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
 
                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
          singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
 
-       /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
-          operation, do this as A + (X != 0).  Similarly for other simple
-          binary operators.  */
+       /* If we are not to produce a result, we have no target.  Otherwise,
+          if a target was specified use it; it will not be used as an
+          intermediate target unless it is safe.  If no target, use a 
+          temporary.  */
+
+       if (ignore)
+         temp = 0;
+       else if (original_target
+                && (safe_from_p (original_target, TREE_OPERAND (exp, 0))
+                    || (singleton && GET_CODE (original_target) == REG
+                        && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
+                        && original_target == var_rtx (singleton)))
+                && GET_MODE (original_target) == mode
+                && ! (GET_CODE (original_target) == MEM
+                      && MEM_VOLATILE_P (original_target)))
+         temp = original_target;
+       else if (TREE_ADDRESSABLE (type))
+         abort ();
+       else
+         temp = assign_temp (type, 0, 0, 1);
+
+       /* If we had X ? A + C : A, with C a constant power of 2, and we can
+          do the test of X as a store-flag operation, do this as
+          A + ((X != 0) << log C).  Similarly for other simple binary
+          operators.  Only do for C == 1 if BRANCH_COST is low.  */
        if (temp && singleton && binary_op
        if (temp && singleton && binary_op
-           && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
            && (TREE_CODE (binary_op) == PLUS_EXPR
                || TREE_CODE (binary_op) == MINUS_EXPR
                || TREE_CODE (binary_op) == BIT_IOR_EXPR
                || TREE_CODE (binary_op) == BIT_XOR_EXPR)
            && (TREE_CODE (binary_op) == PLUS_EXPR
                || TREE_CODE (binary_op) == MINUS_EXPR
                || TREE_CODE (binary_op) == BIT_IOR_EXPR
                || TREE_CODE (binary_op) == BIT_XOR_EXPR)
-           && integer_onep (TREE_OPERAND (binary_op, 1))
+           && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
+               : integer_onep (TREE_OPERAND (binary_op, 1)))
            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
          {
            rtx result;
            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
          {
            rtx result;
@@ -6504,6 +6671,15 @@ expand_expr (exp, target, tmode, modifier)
                                     ? temp : NULL_RTX),
                                    mode, BRANCH_COST <= 1);
 
                                     ? temp : NULL_RTX),
                                    mode, BRANCH_COST <= 1);
 
+           if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
+             result = expand_shift (LSHIFT_EXPR, mode, result,
+                                    build_int_2 (tree_log2
+                                                 (TREE_OPERAND
+                                                  (binary_op, 1)),
+                                                 0),
+                                    (safe_from_p (temp, singleton)
+                                     ? temp : NULL_RTX), 0);
+
            if (result)
              {
                op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
            if (result)
              {
                op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
@@ -7816,8 +7992,8 @@ c_strlen (src)
 rtx
 expand_builtin_return_addr (fndecl_code, count, tem)
      enum built_in_function fndecl_code;
 rtx
 expand_builtin_return_addr (fndecl_code, count, tem)
      enum built_in_function fndecl_code;
-     rtx tem;
      int count;
      int count;
+     rtx tem;
 {
   int i;
 
 {
   int i;
 
@@ -8723,8 +8899,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        enum machine_mode sa_mode = Pmode;
        rtx stack_save;
        int old_inhibit_defer_pop = inhibit_defer_pop;
        enum machine_mode sa_mode = Pmode;
        rtx stack_save;
        int old_inhibit_defer_pop = inhibit_defer_pop;
-       int return_pops = RETURN_POPS_ARGS (get_identifier ("__dummy"),
-                                           get_identifier ("__dummy"), 0);
+       int return_pops
+         =  RETURN_POPS_ARGS (get_identifier ("__dummy"),
+                              build_function_type (void_type_node, NULL_TREE),
+                              0);
        rtx next_arg_reg;
        CUMULATIVE_ARGS args_so_far;
        int i;
        rtx next_arg_reg;
        CUMULATIVE_ARGS args_so_far;
        int i;
@@ -8821,6 +8999,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          }
 #endif
 
          }
 #endif
 
+#ifdef HAVE_nonlocal_goto_receiver
+       if (HAVE_nonlocal_goto_receiver)
+         emit_insn (gen_nonlocal_goto_receiver ());
+#endif
        /* The static chain pointer contains the address of dummy function.
           We need to call it here to handle some PIC cases of restoring
           a global pointer.  Then return 1.  */
        /* The static chain pointer contains the address of dummy function.
           We need to call it here to handle some PIC cases of restoring
           a global pointer.  Then return 1.  */
@@ -9587,6 +9769,22 @@ expand_increment (exp, post, ignore)
 
          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        }
 
          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        }
+      if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
+       {
+         rtx addr = force_reg (Pmode, XEXP (op0, 0));
+         rtx temp, result;
+
+         op0 = change_address (op0, VOIDmode, addr);
+         temp = force_reg (GET_MODE (op0), op0);
+         if (! (*insn_operand_predicate[icode][2]) (op1, mode))
+           op1 = force_reg (mode, op1);
+
+         /* The increment queue is LIFO, thus we have to `queue'
+            the instructions in reverse order.  */
+         enqueue_insn (op0, gen_move_insn (op0, temp));
+         result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
+         return result;
+       }
     }
 
   /* Preincrement, or we can't increment with one simple insn.  */
     }
 
   /* Preincrement, or we can't increment with one simple insn.  */
@@ -9938,9 +10136,9 @@ do_jump (exp, if_false_label, if_true_label)
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
+       cleanups = defer_cleanups_to (old_cleanups);
        end_sequence ();
 
        end_sequence ();
 
-       cleanups = defer_cleanups_to (old_cleanups);
        if (cleanups)
          {
            rtx flag = gen_reg_rtx (word_mode);
        if (cleanups)
          {
            rtx flag = gen_reg_rtx (word_mode);
@@ -10002,9 +10200,9 @@ do_jump (exp, if_false_label, if_true_label)
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
+       cleanups = defer_cleanups_to (old_cleanups);
        end_sequence ();
 
        end_sequence ();
 
-       cleanups = defer_cleanups_to (old_cleanups);
        if (cleanups)
          {
            rtx flag = gen_reg_rtx (word_mode);
        if (cleanups)
          {
            rtx flag = gen_reg_rtx (word_mode);
@@ -10070,11 +10268,13 @@ do_jump (exp, if_false_label, if_true_label)
        tree type;
        tree offset;
        int volatilep = 0;
        tree type;
        tree offset;
        int volatilep = 0;
+       int alignment;
 
        /* Get description of this reference.  We don't actually care
           about the underlying object here.  */
        get_inner_reference (exp, &bitsize, &bitpos, &offset,
 
        /* Get description of this reference.  We don't actually care
           about the underlying object here.  */
        get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                            &mode, &unsignedp, &volatilep);
+                            &mode, &unsignedp, &volatilep,
+                            &alignment);
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
@@ -10101,9 +10301,18 @@ do_jump (exp, if_false_label, if_true_label)
 
       else
        {
 
       else
        {
+         rtx seq1, seq2;
+         tree cleanups_left_side, cleanups_right_side, old_cleanups;
+
          register rtx label1 = gen_label_rtx ();
          drop_through_label = gen_label_rtx ();
          register rtx label1 = gen_label_rtx ();
          drop_through_label = gen_label_rtx ();
+
          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
+
+         /* We need to save the cleanups for the lhs and rhs separately. 
+            Keep track of the cleanups seen before the lhs. */
+         old_cleanups = cleanups_this_call;
+         start_sequence ();
          /* Now the THEN-expression.  */
          do_jump (TREE_OPERAND (exp, 1),
                   if_false_label ? if_false_label : drop_through_label,
          /* Now the THEN-expression.  */
          do_jump (TREE_OPERAND (exp, 1),
                   if_false_label ? if_false_label : drop_through_label,
@@ -10111,10 +10320,71 @@ do_jump (exp, if_false_label, if_true_label)
          /* In case the do_jump just above never jumps.  */
          do_pending_stack_adjust ();
          emit_label (label1);
          /* In case the do_jump just above never jumps.  */
          do_pending_stack_adjust ();
          emit_label (label1);
+         seq1 = get_insns ();
+         /* Now grab the cleanups for the lhs. */
+         cleanups_left_side = defer_cleanups_to (old_cleanups);
+         end_sequence ();
+
+         /* And keep track of where we start before the rhs. */
+         old_cleanups = cleanups_this_call;
+         start_sequence ();
          /* Now the ELSE-expression.  */
          do_jump (TREE_OPERAND (exp, 2),
                   if_false_label ? if_false_label : drop_through_label,
                   if_true_label ? if_true_label : drop_through_label);
          /* Now the ELSE-expression.  */
          do_jump (TREE_OPERAND (exp, 2),
                   if_false_label ? if_false_label : drop_through_label,
                   if_true_label ? if_true_label : drop_through_label);
+         seq2 = get_insns ();
+         /* Grab the cleanups for the rhs. */
+         cleanups_right_side = defer_cleanups_to (old_cleanups);
+         end_sequence ();
+
+         if (cleanups_left_side || cleanups_right_side)
+           {
+             /* Make the cleanups for the THEN and ELSE clauses
+                conditional based on which half is executed. */
+             rtx flag = gen_reg_rtx (word_mode);
+             tree new_cleanups;
+             tree cond;
+
+             /* Set the flag to 0 so that we know we executed the lhs. */
+             emit_move_insn (flag, const0_rtx);
+             emit_insns (seq1);
+
+             /* Set the flag to 1 so that we know we executed the rhs. */
+             emit_move_insn (flag, const1_rtx);
+             emit_insns (seq2);
+
+             /* Make sure the cleanup lives on the function_obstack. */
+             push_obstacks_nochange ();
+             resume_temporary_allocation ();
+
+             /* Now, build up a COND_EXPR that tests the value of the
+                flag, and then either do the cleanups for the lhs or the
+                rhs. */
+             cond = make_node (RTL_EXPR);
+             TREE_TYPE (cond) = integer_type_node;
+             RTL_EXPR_RTL (cond) = flag;
+             RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+             cond = save_expr (cond);
+             
+             new_cleanups = build (COND_EXPR, void_type_node,
+                                   truthvalue_conversion (cond),
+                                   cleanups_right_side, cleanups_left_side);
+             new_cleanups = fold (new_cleanups);
+
+             pop_obstacks ();
+
+             /* Now add in the conditionalized cleanups.  */
+             cleanups_this_call
+               = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+             expand_eh_region_start ();
+           }
+         else 
+           {
+             /* No cleanups were needed, so emit the two sequences
+                directly. */
+             emit_insns (seq1);
+             emit_insns (seq2);
+           }
        }
       break;
 
        }
       break;
 
@@ -10931,7 +11201,7 @@ do_store_flag (exp, target, mode, only_cheap)
     }
 
   /* If this failed, we have to do this with set/compare/jump/set code.  */
     }
 
   /* If this failed, we have to do this with set/compare/jump/set code.  */
-  if (target == 0 || GET_CODE (target) != REG
+  if (GET_CODE (target) != REG
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));
 
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));
 
This page took 0.060894 seconds and 5 git commands to generate.