OSDN Git Service

* crontab: Spread snapshot building more evenly throughout the
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 2434a81..1b91b18 100644 (file)
@@ -1,6 +1,6 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Major work done by Sebastian Pop <s.pop@laposte.net>,
    Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
 
@@ -157,14 +157,14 @@ pop_gimplify_context (tree body)
   gimplify_ctxp = NULL;
 }
 
-void
+static void
 gimple_push_bind_expr (tree bind)
 {
   TREE_CHAIN (bind) = gimplify_ctxp->current_bind_expr;
   gimplify_ctxp->current_bind_expr = bind;
 }
 
-void
+static void
 gimple_pop_bind_expr (void)
 {
   gimplify_ctxp->current_bind_expr
@@ -293,6 +293,7 @@ create_artificial_label (void)
   tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
 
   DECL_ARTIFICIAL (lab) = 1;
+  DECL_IGNORED_P (lab) = 1;
   DECL_CONTEXT (lab) = current_function_decl;
   return lab;
 }
@@ -605,7 +606,7 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
       || TREE_CODE_CLASS (code) == tcc_constant
       || code == SAVE_EXPR || code == TARGET_EXPR
       /* We can't do anything sensible with a BLOCK used as an expression,
-        but we also can't abort when we see it because of non-expression
+        but we also can't just die when we see it because of non-expression
         uses.  So just avert our eyes and cross our fingers.  Silly Java.  */
       || code == BLOCK)
     *walk_subtrees = 0;
@@ -705,7 +706,7 @@ unvisit_body (tree *body_p, tree fndecl)
 
 /* Unshare T and all the trees reached from T via TREE_CHAIN.  */
 
-void
+static void
 unshare_all_trees (tree t)
 {
   walk_tree (&t, copy_if_shared_r, NULL, NULL);
@@ -929,7 +930,7 @@ gimplify_return_expr (tree stmt, tree *pre_p)
      returned in registers.  If we're returning values in registers, then
      we don't want to extend the lifetime of the RESULT_DECL, particularly
      across another call.  In addition, for those aggregates for which
-     hard_function_value generates a PARALLEL, we'll abort during normal
+     hard_function_value generates a PARALLEL, we'll die during normal
      expansion of structure assignments; there's special code in expand_return
      to handle this case that does not exist in expand_expr.  */
   if (!result_decl
@@ -1420,22 +1421,26 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
                        tree *post_p, fallback_t fallback)
 {
   tree *p;
-  varray_type stack;
+  VEC(tree,heap) *stack;
   enum gimplify_status ret = GS_OK, tret;
   int i;
 
   /* Create a stack of the subexpressions so later we can walk them in
-     order from inner to outer.
-
-     This array is very memory consuming.  Don't even think of making
-     it VARRAY_TREE.  */
-  VARRAY_GENERIC_PTR_NOGC_INIT (stack, 10, "stack");
+     order from inner to outer.  */
+  stack = VEC_alloc (tree, heap, 10);
 
   /* We can handle anything that get_inner_reference can deal with.  */
-  for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
-    VARRAY_PUSH_GENERIC_PTR_NOGC (stack, *p);
+  for (p = expr_p; ; p = &TREE_OPERAND (*p, 0))
+    {
+      /* Fold INDIRECT_REFs now to turn them into ARRAY_REFs.  */
+      if (TREE_CODE (*p) == INDIRECT_REF)
+       *p = fold_indirect_ref (*p);
+      if (!handled_component_p (*p))
+       break;
+      VEC_safe_push (tree, heap, stack, *p);
+    }
 
-  gcc_assert (VARRAY_ACTIVE_SIZE (stack));
+  gcc_assert (VEC_length (tree, stack));
 
   /* Now STACK is a stack of pointers to all the refs we've walked through
      and P points to the innermost expression.
@@ -1449,9 +1454,9 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
      So we do this in three steps.  First we deal with the annotations
      for any variables in the components, then we gimplify the base,
      then we gimplify any indices, from left to right.  */
-  for (i = VARRAY_ACTIVE_SIZE (stack) - 1; i >= 0; i--)
+  for (i = VEC_length (tree, stack) - 1; i >= 0; i--)
     {
-      tree t = VARRAY_GENERIC_PTR_NOGC (stack, i);
+      tree t = VEC_index (tree, stack, i);
 
       if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
@@ -1519,9 +1524,9 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
 
   /* And finally, the indices and operands to BIT_FIELD_REF.  During this
      loop we also remove any useless conversions.  */
-  for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
+  for (; VEC_length (tree, stack) > 0; )
     {
-      tree t = VARRAY_TOP_TREE (stack);
+      tree t = VEC_pop (tree, stack);
 
       if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
@@ -1557,7 +1562,6 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
         set which would have caused all the outer expressions in EXPR_P
         leading to P to also have had TREE_SIDE_EFFECTS set.  */
       recalculate_side_effects (t);
-      VARRAY_POP (stack);
     }
 
   tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
@@ -1570,7 +1574,7 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
       ret = MIN (ret, GS_OK);
     }
 
-  VARRAY_FREE (stack);
+  VEC_free (tree, heap, stack);
 
   return ret;
 }
@@ -1736,7 +1740,9 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   decl = get_callee_fndecl (*expr_p);
   if (decl && DECL_BUILT_IN (decl))
     {
-      tree new = fold_builtin (*expr_p, !want_value);
+      tree fndecl = get_callee_fndecl (*expr_p);
+      tree arglist = TREE_OPERAND (*expr_p, 1);
+      tree new = fold_builtin (fndecl, arglist, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -1747,10 +1753,9 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
          return GS_OK;
        }
 
-      if (DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
+      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+         && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
         {
-         tree arglist = TREE_OPERAND (*expr_p, 1);
-         
          if (!arglist || !TREE_CHAIN (arglist))
            {
              error ("too few arguments to function %<va_start%>");
@@ -1793,7 +1798,9 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   /* Try this again in case gimplification exposed something.  */
   if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
     {
-      tree new = fold_builtin (*expr_p, !want_value);
+      tree fndecl = get_callee_fndecl (*expr_p);
+      tree arglist = TREE_OPERAND (*expr_p, 1);
+      tree new = fold_builtin (fndecl, arglist, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -1909,7 +1916,7 @@ shortcut_cond_expr (tree expr)
   tree true_label, false_label, end_label, t;
   tree *true_label_p;
   tree *false_label_p;
-  bool emit_end, emit_false;
+  bool emit_end, emit_false, jump_over_else;
   bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
   bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
 
@@ -1921,6 +1928,7 @@ shortcut_cond_expr (tree expr)
        {
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          then_ = shortcut_cond_expr (expr);
+         then_se = then_ && TREE_SIDE_EFFECTS (then_);
          pred = TREE_OPERAND (pred, 0);
          expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
        }
@@ -1935,6 +1943,7 @@ shortcut_cond_expr (tree expr)
        {
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          else_ = shortcut_cond_expr (expr);
+         else_se = else_ && TREE_SIDE_EFFECTS (else_);
          pred = TREE_OPERAND (pred, 0);
          expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
        }
@@ -2011,6 +2020,16 @@ shortcut_cond_expr (tree expr)
   emit_end = (end_label == NULL_TREE);
   emit_false = (false_label == NULL_TREE);
 
+  /* We only emit the jump over the else clause if we have to--if the
+     then clause may fall through.  Otherwise we can wind up with a
+     useless jump and a useless label at the end of gimplified code,
+     which will cause us to think that this conditional as a whole
+     falls through even if it doesn't.  If we then inline a function
+     which ends with such a condition, that can cause us to issue an
+     inappropriate warning about control reaching the end of a
+     non-void function.  */
+  jump_over_else = block_may_fallthru (then_);
+
   pred = shortcut_cond_r (pred, true_label_p, false_label_p);
 
   expr = NULL;
@@ -2019,8 +2038,11 @@ shortcut_cond_expr (tree expr)
   append_to_statement_list (then_, &expr);
   if (else_se)
     {
-      t = build_and_jump (&end_label);
-      append_to_statement_list (t, &expr);
+      if (jump_over_else)
+       {
+         t = build_and_jump (&end_label);
+         append_to_statement_list (t, &expr);
+       }
       if (emit_false)
        {
          t = build1 (LABEL_EXPR, void_type_node, false_label);
@@ -2047,10 +2069,6 @@ gimple_boolify (tree expr)
   if (TREE_CODE (type) == BOOLEAN_TYPE)
     return expr;
 
-  /* If this is the predicate of a COND_EXPR, it might not even be a
-     truthvalue yet.  */
-  expr = lang_hooks.truthvalue_conversion (expr);
-
   switch (TREE_CODE (expr))
     {
     case TRUTH_AND_EXPR:
@@ -2093,10 +2111,14 @@ gimple_boolify (tree expr)
     TARGET is the tree for T1 above.
 
     PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.  */
+       *EXPR_P should be stored.
+
+   POST_P points to the list where side effects that must happen after
+     *EXPR_P should be stored.  */
 
 static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
+                   fallback_t fallback)
 {
   tree expr = *expr_p;
   tree tmp, tmp2, type;
@@ -2110,18 +2132,40 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
      the arms.  */
   else if (! VOID_TYPE_P (type))
     {
+      tree result;
+
       if (target)
        {
-         ret = gimplify_expr (&target, pre_p, NULL,
+         ret = gimplify_expr (&target, pre_p, post_p,
                               is_gimple_min_lval, fb_lvalue);
          if (ret != GS_ERROR)
            ret = GS_OK;
-         tmp = target;
+         result = tmp = target;
          tmp2 = unshare_expr (target);
        }
+      else if ((fallback & fb_lvalue) == 0)
+       {
+         result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         ret = GS_ALL_DONE;
+       }
       else
        {
-         tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         tree type = build_pointer_type (TREE_TYPE (expr));
+
+         if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+           TREE_OPERAND (expr, 1) =
+             build_fold_addr_expr (TREE_OPERAND (expr, 1));
+
+         if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+           TREE_OPERAND (expr, 2) =
+             build_fold_addr_expr (TREE_OPERAND (expr, 2));
+         
+         tmp2 = tmp = create_tmp_var (type, "iftmp");
+
+         expr = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
+                       TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
+
+         result = build_fold_indirect_ref (tmp);
          ret = GS_ALL_DONE;
        }
 
@@ -2142,7 +2186,7 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
       /* Move the COND_EXPR to the prequeue.  */
       gimplify_and_add (expr, pre_p);
 
-      *expr_p = tmp;
+      *expr_p = result;
       return ret;
     }
 
@@ -2581,11 +2625,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
        categorize_ctor_elements (ctor, &num_nonzero_elements,
                                  &num_nonconstant_elements,
-                                 &num_ctor_elements);
+                                 &num_ctor_elements, &cleared);
 
        /* If a const aggregate variable is being initialized, then it
           should never be a lose to promote the variable to be static.  */
        if (num_nonconstant_elements == 0
+           && num_nonzero_elements > 1
            && TREE_READONLY (object)
            && TREE_CODE (object) == VAR_DECL)
          {
@@ -2667,7 +2712,6 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
        num_type_elements = count_type_elements (TREE_TYPE (ctor));
 
        /* If there are "lots" of zeros, then block clear the object first.  */
-       cleared = false;
        if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
            && num_nonzero_elements < num_type_elements/4)
          cleared = true;
@@ -2756,20 +2800,33 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
     case VECTOR_TYPE:
       /* Go ahead and simplify constant constructors to VECTOR_CST.  */
       if (TREE_CONSTANT (ctor))
-       TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
-      else
        {
-         /* Vector types use CONSTRUCTOR all the way through gimple
-            compilation as a general initializer.  */
-         for (; elt_list; elt_list = TREE_CHAIN (elt_list))
+         tree tem;
+
+         /* Even when ctor is constant, it might contain non-*_CST
+            elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
+            belong into VECTOR_CST nodes.  */
+         for (tem = elt_list; tem; tem = TREE_CHAIN (tem))
+           if (! CONSTANT_CLASS_P (TREE_VALUE (tem)))
+             break;
+
+         if (! tem)
            {
-             enum gimplify_status tret;
-             tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
-                                   is_gimple_val, fb_rvalue);
-             if (tret == GS_ERROR)
-               ret = GS_ERROR;
+             TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
+             break;
            }
        }
+
+      /* Vector types use CONSTRUCTOR all the way through gimple
+        compilation as a general initializer.  */
+      for (; elt_list; elt_list = TREE_CHAIN (elt_list))
+       {
+         enum gimplify_status tret;
+         tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+         if (tret == GS_ERROR)
+           ret = GS_ERROR;
+       }
       break;
 
     default:
@@ -2801,6 +2858,28 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
   while (ret != GS_UNHANDLED)
     switch (TREE_CODE (*from_p))
       {
+      case INDIRECT_REF:
+       {
+         /* If we have code like 
+
+               *(const A*)(A*)&x
+
+            where the type of "x" is a (possibly cv-qualified variant
+            of "A"), treat the entire expression as identical to "x".
+            This kind of code arises in C++ when an object is bound
+            to a const reference, and if "x" is a TARGET_EXPR we want
+            to take advantage of the optimization below.  */
+         tree t = fold_indirect_ref (*from_p);
+         if (t != *from_p)
+           {
+             *from_p = t;
+             ret = GS_OK;
+           }
+         else
+           ret = GS_UNHANDLED;
+         break;
+       }
+
       case TARGET_EXPR:
        {
          /* If we are initializing something from a TARGET_EXPR, strip the
@@ -2810,7 +2889,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
 
             ??? What about code that pulls out the temp and uses it
             elsewhere? I think that such code never uses the TARGET_EXPR as
-            an initializer.  If I'm wrong, we'll abort because the temp won't
+            an initializer.  If I'm wrong, we'll die because the temp won't
             have any RTL.  In that case, I guess we'll need to replace
             references somehow.  */
          tree init = TARGET_EXPR_INITIAL (*from_p);
@@ -2845,7 +2924,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
        if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
          {
            *expr_p = *from_p;
-           return gimplify_cond_expr (expr_p, pre_p, *to_p);
+           return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
+                                      fb_rvalue);
          }
        else
          ret = GS_UNHANDLED;
@@ -3145,6 +3225,9 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
         builtins like __builtin_va_end).  */
       /* Caution: the silent array decomposition semantics we allow for
         ADDR_EXPR means we can't always discard the pair.  */
+      /* Gimplification of the ADDR_EXPR operand may drop
+        cv-qualification conversions, so make sure we add them if
+        needed.  */
       {
        tree op00 = TREE_OPERAND (op0, 0);
        tree t_expr = TREE_TYPE (expr);
@@ -3154,9 +3237,9 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
          {
 #ifdef ENABLE_CHECKING
            tree t_op0 = TREE_TYPE (op0);
-           gcc_assert (TREE_CODE (t_op0) == ARRAY_TYPE
-                       && POINTER_TYPE_P (t_expr)
-                       && cpt_same_type (TREE_TYPE (t_op0),
+           gcc_assert (POINTER_TYPE_P (t_expr)
+                       && cpt_same_type (TREE_CODE (t_op0) == ARRAY_TYPE
+                                         ? TREE_TYPE (t_op0) : t_op0,
                                          TREE_TYPE (t_expr))
                        && POINTER_TYPE_P (t_op00)
                        && cpt_same_type (t_op0, TREE_TYPE (t_op00)));
@@ -3231,10 +3314,6 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
   bool allows_mem, allows_reg, is_inout;
   enum gimplify_status ret, tret;
 
-  ASM_STRING (expr)
-    = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
-                                ASM_INPUTS (expr));
-
   ret = GS_ALL_DONE;
   for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
     {
@@ -3272,16 +3351,81 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
          char *p = xstrdup (constraint);
          p[0] = '=';
          TREE_VALUE (TREE_PURPOSE (link)) = build_string (constraint_len, p);
-         free (p);
 
          /* And add a matching input constraint.  */
          if (allows_reg)
            {
              sprintf (buf, "%d", i);
-             input = build_string (strlen (buf), buf);
+
+             /* If there are multiple alternatives in the constraint,
+                handle each of them individually.  Those that allow register
+                will be replaced with operand number, the others will stay
+                unchanged.  */
+             if (strchr (p, ',') != NULL)
+               {
+                 size_t len = 0, buflen = strlen (buf);
+                 char *beg, *end, *str, *dst;
+
+                 for (beg = p + 1;;)
+                   {
+                     end = strchr (beg, ',');
+                     if (end == NULL)
+                       end = strchr (beg, '\0');
+                     if ((size_t) (end - beg) < buflen)
+                       len += buflen + 1;
+                     else
+                       len += end - beg + 1;
+                     if (*end)
+                       beg = end + 1;
+                     else
+                       break;
+                   }
+
+                 str = alloca (len);
+                 for (beg = p + 1, dst = str;;)
+                   {
+                     const char *tem;
+                     bool mem_p, reg_p, inout_p;
+
+                     end = strchr (beg, ',');
+                     if (end)
+                       *end = '\0';
+                     beg[-1] = '=';
+                     tem = beg - 1;
+                     parse_output_constraint (&tem, i, 0, 0,
+                                              &mem_p, &reg_p, &inout_p);
+                     if (dst != str)
+                       *dst++ = ',';
+                     if (reg_p)
+                       {
+                         memcpy (dst, buf, buflen);
+                         dst += buflen;
+                       }
+                     else
+                       {
+                         if (end)
+                           len = end - beg;
+                         else
+                           len = strlen (beg);
+                         memcpy (dst, beg, len);
+                         dst += len;
+                       }
+                     if (end)
+                       beg = end + 1;
+                     else
+                       break;
+                   }
+                 *dst = '\0';
+                 input = build_string (dst - str, str);
+               }
+             else
+               input = build_string (strlen (buf), buf);
            }
          else
            input = build_string (constraint_len - 1, constraint + 1);
+
+         free (p);
+
          input = build_tree_list (build_tree_list (NULL_TREE, input),
                                   unshare_expr (TREE_VALUE (link)));
          ASM_INPUTS (expr) = chainon (ASM_INPUTS (expr), input);
@@ -3487,7 +3631,7 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
          ret = GS_OK;
           if (TREE_CODE (init) == BIND_EXPR)
            gimplify_bind_expr (&init, temp, pre_p);
-          if (init != temp)
+         if (init != temp)
            {
              init = build (MODIFY_EXPR, void_type_node, temp, init);
              ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
@@ -3663,11 +3807,30 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case COND_EXPR:
-         ret = gimplify_cond_expr (expr_p, pre_p, NULL_TREE);
+         ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
+                                   fallback);
+         /* C99 code may assign to an array in a structure value of a
+            conditional expression, and this has undefined behavior
+            only on execution, so create a temporary if an lvalue is
+            required.  */
+         if (fallback == fb_lvalue)
+           {
+             *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+             lang_hooks.mark_addressable (*expr_p);
+           }
          break;
 
        case CALL_EXPR:
          ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
+         /* C99 code may assign to an array in a structure returned
+            from a function, and this has undefined behavior only on
+            execution, so create a temporary if an lvalue is
+            required.  */
+         if (fallback == fb_lvalue)
+           {
+             *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+             lang_hooks.mark_addressable (*expr_p);
+           }
          break;
 
        case TREE_LIST:
@@ -3738,9 +3901,13 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          recalculate_side_effects (*expr_p);
          break;
 
+       case INDIRECT_REF:
+         *expr_p = fold_indirect_ref (*expr_p);
+         if (*expr_p != save_expr)
+           break;
+         /* else fall through.  */
        case ALIGN_INDIRECT_REF:
        case MISALIGNED_INDIRECT_REF:
-       case INDIRECT_REF:
          ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                               is_gimple_reg, fb_rvalue);
          recalculate_side_effects (*expr_p);
@@ -3914,12 +4081,11 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
        case WITH_SIZE_EXPR:
          {
-           enum gimplify_status r0, r1;
-           r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
-                               post_p == &internal_post ? NULL : post_p,
-                               gimple_test_f, fallback);
-           r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
-                               is_gimple_val, fb_rvalue);
+           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+                          post_p == &internal_post ? NULL : post_p,
+                          gimple_test_f, fallback);
+           gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+                          is_gimple_val, fb_rvalue);
          }
          break;
 
@@ -4159,7 +4325,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 #endif
       gcc_assert (fallback & fb_mayfail);
       /* If this is an asm statement, and the user asked for the
-        impossible, don't abort.  Fail and let gimplify_asm_expr
+        impossible, don't die.  Fail and let gimplify_asm_expr
         issue an error.  */
       ret = GS_ERROR;
       goto out;
@@ -4188,13 +4354,13 @@ gimplify_type_sizes (tree type, tree *list_p)
   tree field, t;
 
   /* Note that we do not check for TYPE_SIZES_GIMPLIFIED already set because
-     that's not supposed to happen on types where gimplifcation does anything.
+     that's not supposed to happen on types where gimplification does anything.
      We should assert that it isn't set, but we can indeed be called multiple
      times on pointers.  Unfortunately, this includes fat pointers which we
      can't easily test for.  We could pass TYPE down to gimplify_one_sizepos
      and test there, but it doesn't seem worth it.  */
 
-  /* We first do the main variant, then copy into any other variants. */
+  /* We first do the main variant, then copy into any other variants.  */
   type = TYPE_MAIN_VARIANT (type);
 
   switch (TREE_CODE (type))
@@ -4261,7 +4427,7 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
 {
   /* We don't do anything if the value isn't there, is constant, or contains
      A PLACEHOLDER_EXPR.  We also don't want to do anything if it's already
-     a VAR_DECL.  If it's a VAR_DECL from another function, the gimplfier
+     a VAR_DECL.  If it's a VAR_DECL from another function, the gimplifier
      will want to replace it with a new variable, but that will cause problems
      if this type is from outside the function.  It's OK to have that here.  */
   if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
@@ -4492,7 +4658,7 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
   gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
 
   push_gimplify_context ();
-  gimplify_ctxp->into_ssa = true;
+  gimplify_ctxp->into_ssa = in_ssa_p;
 
   if (var)
     expr = build (MODIFY_EXPR, TREE_TYPE (var), var, expr);
@@ -4501,12 +4667,31 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
                       gimple_test_f, fb_rvalue);
   gcc_assert (ret != GS_ERROR);
 
-  for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
-    add_referenced_tmp_var (t);
+  if (referenced_vars)
+    {
+      for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
+       add_referenced_tmp_var (t);
+    }
 
   pop_gimplify_context (NULL);
 
   return expr;
 }
 
+/* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR.  If
+   some statements are produced, emits them before BSI.  */
+
+tree
+force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
+                         bool simple_p, tree var)
+{
+  tree stmts;
+
+  expr = force_gimple_operand (expr, &stmts, simple_p, var);
+  if (stmts)
+    bsi_insert_before (bsi, stmts, BSI_SAME_STMT);
+
+  return expr;
+}
+
 #include "gt-gimplify.h"