OSDN Git Service

PR rtl-optimization/44374
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 855098f..4e6a037 100644 (file)
@@ -26,33 +26,31 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "gimple.h"
 #include "tree-iterator.h"
 #include "tree-inline.h"
-#include "diagnostic.h"
 #include "tree-pretty-print.h"
 #include "langhooks.h"
-#include "langhooks-def.h"
 #include "tree-flow.h"
 #include "cgraph.h"
 #include "timevar.h"
-#include "except.h"
 #include "hashtab.h"
 #include "flags.h"
 #include "function.h"
 #include "output.h"
-#include "expr.h"
 #include "ggc.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "target.h"
-#include "optabs.h"
 #include "pointer-set.h"
 #include "splay-tree.h"
 #include "vec.h"
 #include "gimple.h"
 #include "tree-pass.h"
 
+#include "langhooks-def.h"     /* FIXME: for lhd_set_decl_assembler_name.  */
+#include "expr.h"              /* FIXME: for can_move_by_pieces
+                                  and STACK_CHECK_MAX_VAR_SIZE.  */
 
 enum gimplify_omp_var_data
 {
@@ -113,10 +111,13 @@ mark_addressable (tree x)
 {
   while (handled_component_p (x))
     x = TREE_OPERAND (x, 0);
+  if (TREE_CODE (x) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
+    x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
   if (TREE_CODE (x) != VAR_DECL
       && TREE_CODE (x) != PARM_DECL
       && TREE_CODE (x) != RESULT_DECL)
-    return ;
+    return;
   TREE_ADDRESSABLE (x) = 1;
 }
 
@@ -537,7 +538,7 @@ lookup_tmp_var (tree val, bool is_formal)
 
 
 /* Return true if T is a CALL_EXPR or an expression that can be
-   assignmed to a temporary.  Note that this predicate should only be
+   assigned to a temporary.  Note that this predicate should only be
    used during gimplification.  See the rationale for this in
    gimplify_modify_expr.  */
 
@@ -652,7 +653,7 @@ declare_vars (tree vars, gimple scope, bool debug_info)
       gcc_assert (!block || TREE_CODE (block) == BLOCK);
       if (!block || !debug_info)
        {
-         TREE_CHAIN (last) = gimple_bind_vars (scope);
+         DECL_CHAIN (last) = gimple_bind_vars (scope);
          gimple_bind_set_vars (scope, temps);
        }
       else
@@ -700,7 +701,7 @@ force_constant_size (tree var)
 void
 gimple_add_tmp_var (tree tmp)
 {
-  gcc_assert (!TREE_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
+  gcc_assert (!DECL_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
 
   /* Later processing assumes that the object size is constant, which might
      not be true at this point.  Force the use of a constant upper bound in
@@ -713,7 +714,7 @@ gimple_add_tmp_var (tree tmp)
 
   if (gimplify_ctxp)
     {
-      TREE_CHAIN (tmp) = gimplify_ctxp->temps;
+      DECL_CHAIN (tmp) = gimplify_ctxp->temps;
       gimplify_ctxp->temps = tmp;
 
       /* Mark temporaries local within the nearest enclosing parallel.  */
@@ -868,9 +869,9 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
   tree t = *tp;
   enum tree_code code = TREE_CODE (t);
 
-  /* Do not copy SAVE_EXPR or TARGET_EXPR nodes themselves, but copy
-     their subtrees if we can make sure to do it only once.  */
-  if (code == SAVE_EXPR || code == TARGET_EXPR)
+  /* Do not copy SAVE_EXPR, TARGET_EXPR or BIND_EXPR nodes themselves, but
+     copy their subtrees if we can make sure to do it only once.  */
+  if (code == SAVE_EXPR || code == TARGET_EXPR || code == BIND_EXPR)
     {
       if (data && !pointer_set_insert ((struct pointer_set_t *)data, t))
        ;
@@ -895,10 +896,7 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
 
   /* Leave the bulk of the work to copy_tree_r itself.  */
   else
-    {
-      gcc_assert (code != BIND_EXPR);
-      copy_tree_r (tp, walk_subtrees, NULL);
-    }
+    copy_tree_r (tp, walk_subtrees, NULL);
 
   return NULL_TREE;
 }
@@ -1135,7 +1133,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
   tree temp = voidify_wrapper_expr (bind_expr, NULL);
 
   /* Mark variables seen in this bind expr.  */
-  for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
+  for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t))
     {
       if (TREE_CODE (t) == VAR_DECL)
        {
@@ -1156,14 +1154,9 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 
       /* Preliminarily mark non-addressed complex variables as eligible
         for promotion to gimple registers.  We'll transform their uses
-        as we find them.
-        We exclude complex types if not optimizing because they can be
-        subject to partial stores in GNU C by means of the __real__ and
-        __imag__ operators and we cannot promote them to total stores
-        (see gimplify_modify_expr_complex_part).  */
-      if (optimize
-         && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
-             || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+        as we find them.  */
+      if ((TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+          || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
          && !TREE_THIS_VOLATILE (t)
          && (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t))
          && !needs_to_live_in_memory (t))
@@ -1336,6 +1329,8 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 
   t = built_in_decls[BUILT_IN_ALLOCA];
   t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl));
+  /* The call has been built for a variable-sized object.  */
+  ALLOCA_FOR_VAR_P (t) = 1;
   t = fold_convert (ptr_type, t);
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
@@ -1906,10 +1901,10 @@ gimplify_var_or_parm_decl (tree *expr_p)
              tree copy = copy_node (decl), block;
 
              lang_hooks.dup_lang_specific_decl (copy);
-             SET_DECL_RTL (copy, NULL_RTX);
+             SET_DECL_RTL (copy, 0);
              TREE_USED (copy) = 1;
              block = DECL_INITIAL (current_function_decl);
-             TREE_CHAIN (copy) = BLOCK_VARS (block);
+             DECL_CHAIN (copy) = BLOCK_VARS (block);
              BLOCK_VARS (block) = copy;
              SET_DECL_VALUE_EXPR (copy, unshare_expr (value_expr));
              DECL_HAS_VALUE_EXPR_P (copy) = 1;
@@ -2484,8 +2479,11 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
     {
       /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
         have to do is replicate it as a GIMPLE_CALL tuple.  */
+      gimple_stmt_iterator gsi;
       call = gimple_build_call_from_tree (*expr_p);
       gimplify_seq_add_stmt (pre_p, call);
+      gsi = gsi_last (*pre_p);
+      fold_stmt (&gsi);
       *expr_p = NULL_TREE;
     }
 
@@ -2969,7 +2967,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
            = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
 
          tmp = create_tmp_var (type, "iftmp");
-         result = build_fold_indirect_ref_loc (loc, tmp);
+         result = build_simple_mem_ref_loc (loc, tmp);
        }
 
       /* Build the new then clause, `tmp = then_;'.  But don't build the
@@ -3193,7 +3191,7 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value,
       gimple_call_set_lhs (gs, t);
       gimplify_seq_add_stmt (seq_p, gs);
 
-      *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+      *expr_p = build_simple_mem_ref (t);
       return GS_ALL_DONE;
     }
 
@@ -3277,13 +3275,16 @@ gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata)
   /* If the constructor component is indirect, determine if we have a
      potential overlap with the lhs.  The only bits of information we
      have to go on at this point are addressability and alias sets.  */
-  if (TREE_CODE (t) == INDIRECT_REF
+  if ((INDIRECT_REF_P (t)
+       || TREE_CODE (t) == MEM_REF)
       && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
       && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
     return t;
 
   /* If the constructor component is a call, determine if it can hide a
-     potential overlap with the lhs through an INDIRECT_REF like above.  */
+     potential overlap with the lhs through an INDIRECT_REF like above.
+     ??? Ugh - this is completely broken.  In fact this whole analysis
+     doesn't look conservative.  */
   if (TREE_CODE (t) == CALL_EXPR)
     {
       tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t)));
@@ -3332,7 +3333,7 @@ gimplify_init_ctor_preeval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       constructor_elt *ce;
       VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (*expr_p);
 
-      for (ix = 0; VEC_iterate (constructor_elt, v, ix, ce); ix++)
+      FOR_EACH_VEC_ELT (constructor_elt, v, ix, ce)
        gimplify_init_ctor_preeval (&ce->value, pre_p, post_p, data);
 
       return;
@@ -3826,11 +3827,12 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
              }
          }
 
-       /* If the target is volatile and we have non-zero elements
-          initialize the target from a temporary.  */
+       /* If the target is volatile, we have non-zero elements and more than
+          one field to assign, initialize the target from a temporary.  */
        if (TREE_THIS_VOLATILE (object)
            && !TREE_ADDRESSABLE (type)
-           && num_nonzero_elements > 0)
+           && num_nonzero_elements > 0
+           && VEC_length (constructor_elt, elts) > 1)
          {
            tree temp = create_tmp_var (TYPE_MAIN_VARIANT (type), NULL);
            TREE_OPERAND (*expr_p, 0) = temp;
@@ -3961,7 +3963,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
        /* Vector types use CONSTRUCTOR all the way through gimple
          compilation as a general initializer.  */
-       for (ix = 0; VEC_iterate (constructor_elt, elts, ix, ce); ix++)
+       FOR_EACH_VEC_ELT (constructor_elt, elts, ix, ce)
          {
            enum gimplify_status tret;
            tret = gimplify_expr (&ce->value, pre_p, post_p, is_gimple_val,
@@ -4012,7 +4014,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 tree
 gimple_fold_indirect_ref (tree t)
 {
-  tree type = TREE_TYPE (TREE_TYPE (t));
+  tree ptype = TREE_TYPE (t), type = TREE_TYPE (ptype);
   tree sub = t;
   tree subtype;
 
@@ -4055,51 +4057,52 @@ gimple_fold_indirect_ref (tree t)
         }
     }
 
-  /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
+  /* *(p + CST) -> ...  */
   if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
     {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
+      tree addr = TREE_OPERAND (sub, 0);
+      tree off = TREE_OPERAND (sub, 1);
+      tree addrtype;
 
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-         && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
-         && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
+      STRIP_NOPS (addr);
+      addrtype = TREE_TYPE (addr);
+
+      /* ((foo*)&vectorfoo)[1] -> BIT_FIELD_REF<vectorfoo,...> */
+      if (TREE_CODE (addr) == ADDR_EXPR
+         && TREE_CODE (TREE_TYPE (addrtype)) == VECTOR_TYPE
+         && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
        {
-         HOST_WIDE_INT offset = tree_low_cst (op01, 0);
-         tree part_width = TYPE_SIZE (type);
-         unsigned HOST_WIDE_INT part_widthi
-           = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
-         unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
-         tree index = bitsize_int (indexi);
-         if (offset / part_widthi
-             <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
-           return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
-                               part_width, index);
+          HOST_WIDE_INT offset = tree_low_cst (off, 0);
+          tree part_width = TYPE_SIZE (type);
+          unsigned HOST_WIDE_INT part_widthi
+            = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
+          unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+          tree index = bitsize_int (indexi);
+          if (offset / part_widthi
+              <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (addrtype)))
+            return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (addr, 0),
+                                part_width, index);
        }
-    }
 
-  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-  if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-      && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
-    {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
+      /* ((foo*)&complexfoo)[1] -> __imag__ complexfoo */
+      if (TREE_CODE (addr) == ADDR_EXPR
+         && TREE_CODE (TREE_TYPE (addrtype)) == COMPLEX_TYPE
+         && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
+        {
+          tree size = TYPE_SIZE_UNIT (type);
+          if (tree_int_cst_equal (size, off))
+            return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (addr, 0));
+        }
 
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-         && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
-         && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
-       {
-         tree size = TYPE_SIZE_UNIT (type);
-         if (tree_int_cst_equal (size, op01))
-           return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0));
-       }
+      /* *(p + CST) -> MEM_REF <p, CST>.  */
+      if (TREE_CODE (addr) != ADDR_EXPR
+         || DECL_P (TREE_OPERAND (addr, 0)))
+       return fold_build2 (MEM_REF, type,
+                           addr,
+                           build_int_cst_wide (ptype,
+                                               TREE_INT_CST_LOW (off),
+                                               TREE_INT_CST_HIGH (off)));
     }
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
@@ -4197,9 +4200,18 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
             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.  */
+           bool volatile_p = TREE_THIS_VOLATILE (*from_p);
            tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
            if (t)
              {
+               if (TREE_THIS_VOLATILE (t) != volatile_p)
+                 {
+                   if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
+                     t = build_simple_mem_ref_loc (EXPR_LOCATION (*from_p),
+                                                   build_fold_addr_expr (t));
+                   if (REFERENCE_CLASS_P (t))
+                     TREE_THIS_VOLATILE (t) = volatile_p;
+                 }
                *from_p = t;
                ret = GS_OK;
                changed = true;
@@ -4240,6 +4252,10 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
          break;
 
        case CONSTRUCTOR:
+         /* If we already made some changes, let the front end have a
+            crack at this before we break it down.  */
+         if (ret != GS_UNHANDLED)
+           break;
          /* If we're initializing from a CONSTRUCTOR, break this into
             individual MODIFY_EXPRs.  */
          return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
@@ -4563,7 +4579,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   /* Try to alleviate the effects of the gimplification creating artificial
      temporaries (see for example is_gimple_reg_rhs) on the debug info.  */
   if (!gimplify_ctxp->into_ssa
-      && DECL_P (*from_p)
+      && TREE_CODE (*from_p) == VAR_DECL
       && DECL_IGNORED_P (*from_p)
       && DECL_P (*to_p)
       && !DECL_IGNORED_P (*to_p))
@@ -4575,6 +4591,9 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       SET_DECL_DEBUG_EXPR (*from_p, *to_p);
    }
 
+  if (want_value && TREE_THIS_VOLATILE (*to_p))
+    *from_p = get_initialized_tmp_var (*from_p, pre_p, post_p);
+
   if (TREE_CODE (*from_p) == CALL_EXPR)
     {
       /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
@@ -4602,7 +4621,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   if (want_value)
     {
-      *expr_p = unshare_expr (*to_p);
+      *expr_p = TREE_THIS_VOLATILE (*to_p) ? *from_p : unshare_expr (*to_p);
       return GS_OK;
     }
   else
@@ -4784,7 +4803,6 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
   switch (TREE_CODE (op0))
     {
     case INDIRECT_REF:
-    case MISALIGNED_INDIRECT_REF:
     do_indirect_ref:
       /* Check if we are dealing with an expression of the form '&*ptr'.
         While the front end folds away '&*ptr' into 'ptr', these
@@ -5143,9 +5161,10 @@ gimplify_cleanup_point_expr (tree *expr_p, gimple_seq *pre_p)
            {
               /* Note that gsi_insert_seq_before and gsi_remove do not
                  scan operands, unlike some other sequence mutators.  */
-             gsi_insert_seq_before_without_update (&iter,
-                                                    gimple_wce_cleanup (wce),
-                                                    GSI_SAME_STMT);
+             if (!gimple_wce_cleanup_eh_only (wce))
+               gsi_insert_seq_before_without_update (&iter,
+                                                     gimple_wce_cleanup (wce),
+                                                     GSI_SAME_STMT);
              gsi_remove (&iter, true);
              break;
            }
@@ -5394,7 +5413,7 @@ omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type)
     case QUAL_UNION_TYPE:
       {
        tree field;
-       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
          if (TREE_CODE (field) == FIELD_DECL)
            {
              omp_firstprivatize_variable (ctx, DECL_FIELD_OFFSET (field));
@@ -5588,7 +5607,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
        {
        case OMP_CLAUSE_DEFAULT_NONE:
          error ("%qE not specified in enclosing parallel",
-                DECL_NAME (decl));
+                DECL_NAME (lang_hooks.decls.omp_report_decl (decl)));
          if ((ctx->region_type & ORT_TASK) != 0)
            error_at (ctx->location, "enclosing task");
          else
@@ -6400,8 +6419,12 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr,
        {
        case TRUTH_ANDIF_EXPR:
        case TRUTH_ORIF_EXPR:
+       case TRUTH_AND_EXPR:
+       case TRUTH_OR_EXPR:
+       case TRUTH_XOR_EXPR:
          saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
                                         lhs_addr, lhs_var);
+       case TRUTH_NOT_EXPR:
          saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
                                         lhs_addr, lhs_var);
          break;
@@ -6516,7 +6539,7 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
 
    GIMPLE_TEST_F points to a function that takes a tree T and
        returns nonzero if T is in the GIMPLE form requested by the
-       caller.  The GIMPLE predicates are in tree-gimple.c.
+       caller.  The GIMPLE predicates are in gimple.c.
 
    FALLBACK tells the function what sort of a temporary we want if
        gimplification cannot produce an expression that complies with
@@ -6565,7 +6588,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            || gimple_test_f == is_gimple_mem_rhs_or_call
            || gimple_test_f == is_gimple_reg_rhs
            || gimple_test_f == is_gimple_reg_rhs_or_call
-           || gimple_test_f == is_gimple_asm_val)
+           || gimple_test_f == is_gimple_asm_val
+          || gimple_test_f == is_gimple_mem_ref_addr)
     gcc_assert (fallback & fb_rvalue);
   else if (gimple_test_f == is_gimple_min_lval
           || gimple_test_f == is_gimple_lvalue)
@@ -6772,18 +6796,47 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          break;
 
        case INDIRECT_REF:
-         *expr_p = fold_indirect_ref_loc (input_location, *expr_p);
-         if (*expr_p != save_expr)
+         {
+           bool volatilep = TREE_THIS_VOLATILE (*expr_p);
+           tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
+
+           *expr_p = fold_indirect_ref_loc (input_location, *expr_p);
+           if (*expr_p != save_expr)
+             {
+               ret = GS_OK;
+               break;
+             }
+
+           ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                                is_gimple_reg, fb_rvalue);
+           recalculate_side_effects (*expr_p);
+
+           *expr_p = fold_build2_loc (input_location, MEM_REF,
+                                      TREE_TYPE (*expr_p),
+                                      TREE_OPERAND (*expr_p, 0),
+                                      build_int_cst (saved_ptr_type, 0));
+           TREE_THIS_VOLATILE (*expr_p) = volatilep;
+           ret = GS_OK;
+           break;
+         }
+
+       /* We arrive here through the various re-gimplifcation paths.  */
+       case MEM_REF:
+         /* First try re-folding the whole thing.  */
+         tmp = fold_binary (MEM_REF, TREE_TYPE (*expr_p),
+                            TREE_OPERAND (*expr_p, 0),
+                            TREE_OPERAND (*expr_p, 1));
+         if (tmp)
            {
+             *expr_p = tmp;
+             recalculate_side_effects (*expr_p);
              ret = GS_OK;
              break;
            }
-         /* else fall through.  */
-       case ALIGN_INDIRECT_REF:
-       case MISALIGNED_INDIRECT_REF:
          ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                              is_gimple_reg, fb_rvalue);
+                              is_gimple_mem_ref_addr, fb_rvalue);
          recalculate_side_effects (*expr_p);
+         ret = GS_ALL_DONE;
          break;
 
          /* Constants need not be gimplified.  */
@@ -6875,14 +6928,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          if (fallback == fb_none)
            {
              unsigned HOST_WIDE_INT ix;
-             constructor_elt *ce;
+             tree val;
              tree temp = NULL_TREE;
-             for (ix = 0;
-                  VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (*expr_p),
-                               ix, ce);
-                  ix++)
-               if (TREE_SIDE_EFFECTS (ce->value))
-                 append_to_statement_list (ce->value, &temp);
+             FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (*expr_p), ix, val)
+               if (TREE_SIDE_EFFECTS (val))
+                 append_to_statement_list (val, &temp);
 
              *expr_p = temp;
              ret = temp ? GS_OK : GS_ALL_DONE;
@@ -6930,15 +6980,15 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          {
            enum gimplify_status r0 = GS_ALL_DONE, r1 = GS_ALL_DONE;
 
-           if (TMR_SYMBOL (*expr_p))
-             r0 = gimplify_expr (&TMR_SYMBOL (*expr_p), pre_p,
-                                 post_p, is_gimple_lvalue, fb_either);
-           else if (TMR_BASE (*expr_p))
+           if (TMR_BASE (*expr_p))
              r0 = gimplify_expr (&TMR_BASE (*expr_p), pre_p,
-                                 post_p, is_gimple_val, fb_either);
+                                 post_p, is_gimple_mem_ref_addr, fb_either);
            if (TMR_INDEX (*expr_p))
              r1 = gimplify_expr (&TMR_INDEX (*expr_p), pre_p,
                                  post_p, is_gimple_val, fb_rvalue);
+           if (TMR_INDEX2 (*expr_p))
+             r1 = gimplify_expr (&TMR_INDEX2 (*expr_p), pre_p,
+                                 post_p, is_gimple_val, fb_rvalue);
            /* TMR_STEP and TMR_OFFSET are always integer constants.  */
            ret = MIN (r0, r1);
          }
@@ -7380,7 +7430,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
         that temporary.  */
       tmp = build_fold_addr_expr_loc (input_location, *expr_p);
       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
-      *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp);
+      *expr_p = build_simple_mem_ref (tmp);
     }
   else if ((fallback & fb_rvalue) && is_gimple_reg_rhs_or_call (*expr_p))
     {
@@ -7496,7 +7546,7 @@ gimplify_type_sizes (tree type, gimple_seq *list_p)
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL)
          {
            gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
@@ -7655,7 +7705,7 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
       gimple_bind_set_body (outer_bind, parm_stmts);
 
       for (parm = DECL_ARGUMENTS (current_function_decl);
-          parm; parm = TREE_CHAIN (parm))
+          parm; parm = DECL_CHAIN (parm))
        if (DECL_HAS_VALUE_EXPR_P (parm))
          {
            DECL_HAS_VALUE_EXPR_P (parm) = 0;
@@ -7705,7 +7755,7 @@ gimplify_function_tree (tree fndecl)
   else
     push_struct_function (fndecl);
 
-  for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
+  for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = DECL_CHAIN (parm))
     {
       /* Preliminarily mark non-addressed complex variables as eligible
          for promotion to gimple registers.  We'll transform their uses
@@ -7961,17 +8011,16 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
 }
 
 
-/* Expands EXPR to list of gimple statements STMTS.  If SIMPLE is true,
-   force the result to be either ssa_name or an invariant, otherwise
-   just force it to be a rhs expression.  If VAR is not NULL, make the
+/* Expands EXPR to list of gimple statements STMTS.  GIMPLE_TEST_F specifies
+   the predicate that will hold for the result.  If VAR is not NULL, make the
    base variable of the final destination be VAR if suitable.  */
 
 tree
-force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
+force_gimple_operand_1 (tree expr, gimple_seq *stmts,
+                       gimple_predicate gimple_test_f, tree var)
 {
   tree t;
   enum gimplify_status ret;
-  gimple_predicate gimple_test_f;
   struct gimplify_ctx gctx;
 
   *stmts = NULL;
@@ -7979,8 +8028,6 @@ force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
   if (is_gimple_val (expr))
     return expr;
 
-  gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
-
   push_gimplify_context (&gctx);
   gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
   gimplify_ctxp->allow_rhs_cond_expr = true;
@@ -8001,7 +8048,7 @@ force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
     }
 
   if (gimple_referenced_vars (cfun))
-    for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
+    for (t = gimplify_ctxp->temps; t ; t = DECL_CHAIN (t))
       add_referenced_var (t);
 
   pop_gimplify_context (NULL);
@@ -8009,20 +8056,34 @@ force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
   return expr;
 }
 
-/* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR.  If
-   some statements are produced, emits them at GSI.  If BEFORE is true.
-   the statements are appended before GSI, otherwise they are appended after
-   it.  M specifies the way GSI moves after insertion (GSI_SAME_STMT or
-   GSI_CONTINUE_LINKING are the usual values).  */
+/* Expands EXPR to list of gimple statements STMTS.  If SIMPLE is true,
+   force the result to be either ssa_name or an invariant, otherwise
+   just force it to be a rhs expression.  If VAR is not NULL, make the
+   base variable of the final destination be VAR if suitable.  */
 
 tree
-force_gimple_operand_gsi (gimple_stmt_iterator *gsi, tree expr,
-                         bool simple_p, tree var, bool before,
-                         enum gsi_iterator_update m)
+force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
+{
+  return force_gimple_operand_1 (expr, stmts,
+                                simple ? is_gimple_val : is_gimple_reg_rhs,
+                                var);
+}
+
+/* Invokes force_gimple_operand_1 for EXPR with parameters GIMPLE_TEST_F
+   and VAR.  If some statements are produced, emits them at GSI.
+   If BEFORE is true.  the statements are appended before GSI, otherwise
+   they are appended after it.  M specifies the way GSI moves after
+   insertion (GSI_SAME_STMT or GSI_CONTINUE_LINKING are the usual values).  */
+
+tree
+force_gimple_operand_gsi_1 (gimple_stmt_iterator *gsi, tree expr,
+                           gimple_predicate gimple_test_f,
+                           tree var, bool before,
+                           enum gsi_iterator_update m)
 {
   gimple_seq stmts;
 
-  expr = force_gimple_operand (expr, &stmts, simple_p, var);
+  expr = force_gimple_operand_1 (expr, &stmts, gimple_test_f, var);
 
   if (!gimple_seq_empty_p (stmts))
     {
@@ -8043,4 +8104,24 @@ force_gimple_operand_gsi (gimple_stmt_iterator *gsi, tree expr,
   return expr;
 }
 
+/* Invokes force_gimple_operand_1 for EXPR with parameter VAR.
+   If SIMPLE is true, force the result to be either ssa_name or an invariant,
+   otherwise just force it to be a rhs expression.  If some statements are
+   produced, emits them at GSI.  If BEFORE is true, the statements are
+   appended before GSI, otherwise they are appended after it.  M specifies
+   the way GSI moves after insertion (GSI_SAME_STMT or GSI_CONTINUE_LINKING
+   are the usual values).  */
+
+tree
+force_gimple_operand_gsi (gimple_stmt_iterator *gsi, tree expr,
+                         bool simple_p, tree var, bool before,
+                         enum gsi_iterator_update m)
+{
+  return force_gimple_operand_gsi_1 (gsi, expr,
+                                    simple_p
+                                    ? is_gimple_val : is_gimple_reg_rhs,
+                                    var, before, m);
+}
+
+
 #include "gt-gimplify.h"