OSDN Git Service

* gcc.dg/pr34351.c: Compile for x86 targets only. Use %ebx register.
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index ab2efac..04ed39c 100644 (file)
@@ -1,6 +1,7 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   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>.
 
    Major work done by Sebastian Pop <s.pop@laposte.net>,
    Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
 
@@ -8,7 +9,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -17,9 +18,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -48,6 +48,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "optabs.h"
 #include "pointer-set.h"
 #include "target.h"
 #include "optabs.h"
 #include "pointer-set.h"
+#include "splay-tree.h"
 
 
 enum gimplify_omp_var_data
 
 
 enum gimplify_omp_var_data
@@ -93,6 +94,7 @@ struct gimplify_ctx
   int conditions;
   bool save_stack;
   bool into_ssa;
   int conditions;
   bool save_stack;
   bool into_ssa;
+  bool allow_rhs_cond_expr;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -111,10 +113,18 @@ typedef struct gimple_temp_hash_elt
 
 /* Forward declarations.  */
 static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
 
 /* Forward declarations.  */
 static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
-#ifdef ENABLE_CHECKING
-static bool cpt_same_type (tree a, tree b);
-#endif
 
 
+/* Mark X addressable.  Unlike the langhook we expect X to be in gimple
+   form and we don't do any syntax checking.  */
+static void
+mark_addressable (tree x)
+{
+  while (handled_component_p (x))
+    x = TREE_OPERAND (x, 0);
+  if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
+    return ;
+  TREE_ADDRESSABLE (x) = 1;
+}
 
 /* Return a hash value for a formal temporary table entry.  */
 
 
 /* Return a hash value for a formal temporary table entry.  */
 
@@ -496,9 +506,9 @@ create_tmp_var (tree type, const char *prefix)
     I.E. given  <temp> = &A, return A.  */
 
 const char *
     I.E. given  <temp> = &A, return A.  */
 
 const char *
-get_name (tree t)
+get_name (const_tree t)
 {
 {
-  tree stripped_decl;
+  const_tree stripped_decl;
 
   stripped_decl = t;
   STRIP_NOPS (stripped_decl);
 
   stripped_decl = t;
   STRIP_NOPS (stripped_decl);
@@ -606,8 +616,9 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
        }
     }
 
        }
     }
 
-  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
-    DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
+  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (t) = 1;
 
   mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
 
 
   mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
 
@@ -751,7 +762,7 @@ gimple_add_tmp_var (tree tmp)
 /* Determines whether to assign a locus to the statement STMT.  */
 
 static bool
 /* Determines whether to assign a locus to the statement STMT.  */
 
 static bool
-should_carry_locus_p (tree stmt)
+should_carry_locus_p (const_tree stmt)
 {
   /* Don't emit a line note for a label.  We particularly don't want to
      emit one for the break label, since it doesn't actually correspond
 {
   /* Don't emit a line note for a label.  We particularly don't want to
      emit one for the break label, since it doesn't actually correspond
@@ -769,7 +780,8 @@ should_carry_locus_p (tree stmt)
 static void
 annotate_one_with_locus (tree t, location_t locus)
 {
 static void
 annotate_one_with_locus (tree t, location_t locus)
 {
-  if (EXPR_P (t) && ! EXPR_HAS_LOCATION (t) && should_carry_locus_p (t))
+  if (CAN_HAVE_LOCATION_P (t)
+      && ! EXPR_HAS_LOCATION (t) && should_carry_locus_p (t))
     SET_EXPR_LOCATION (t, locus);
 }
 
     SET_EXPR_LOCATION (t, locus);
 }
 
@@ -1011,8 +1023,9 @@ voidify_wrapper_expr (tree wrapper, tree temp)
          /* The wrapper is on the RHS of an assignment that we're pushing
             down.  */
          gcc_assert (TREE_CODE (temp) == INIT_EXPR
          /* The wrapper is on the RHS of an assignment that we're pushing
             down.  */
          gcc_assert (TREE_CODE (temp) == INIT_EXPR
+                     || TREE_CODE (temp) == GIMPLE_MODIFY_STMT
                      || TREE_CODE (temp) == MODIFY_EXPR);
                      || TREE_CODE (temp) == MODIFY_EXPR);
-         TREE_OPERAND (temp, 1) = *p;
+         GENERIC_TREE_OPERAND (temp, 1) = *p;
          *p = temp;
        }
       else
          *p = temp;
        }
       else
@@ -1036,14 +1049,13 @@ build_stack_save_restore (tree *save, tree *restore)
   tree save_call, tmp_var;
 
   save_call =
   tree save_call, tmp_var;
 
   save_call =
-      build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE],
-                               NULL_TREE);
+    build_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE], 0);
   tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
 
   tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
 
-  *save = build2 (MODIFY_EXPR, ptr_type_node, tmp_var, save_call);
+  *save = build_gimple_modify_stmt (tmp_var, save_call);
   *restore =
   *restore =
-    build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE],
-                             tree_cons (NULL_TREE, tmp_var, NULL_TREE));
+    build_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE],
+                    1, tmp_var);
 }
 
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
 }
 
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
@@ -1077,11 +1089,12 @@ gimplify_bind_expr (tree *expr_p, tree *pre_p)
       /* Preliminarily mark non-addressed complex variables as eligible
         for promotion to gimple registers.  We'll transform their uses
         as we find them.  */
       /* Preliminarily mark non-addressed complex variables as eligible
         for promotion to gimple registers.  We'll transform their uses
         as we find them.  */
-      if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      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))
          && !TREE_THIS_VOLATILE (t)
          && (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t))
          && !needs_to_live_in_memory (t))
-       DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
+       DECL_GIMPLE_REG_P (t) = 1;
     }
 
   gimple_push_bind_expr (bind_expr);
     }
 
   gimple_push_bind_expr (bind_expr);
@@ -1141,12 +1154,13 @@ gimplify_return_expr (tree stmt, tree *pre_p)
     result_decl = NULL_TREE;
   else
     {
     result_decl = NULL_TREE;
   else
     {
-      result_decl = TREE_OPERAND (ret_expr, 0);
+      result_decl = GENERIC_TREE_OPERAND (ret_expr, 0);
       if (TREE_CODE (result_decl) == INDIRECT_REF)
        /* See through a return by reference.  */
        result_decl = TREE_OPERAND (result_decl, 0);
 
       gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR
       if (TREE_CODE (result_decl) == INDIRECT_REF)
        /* See through a return by reference.  */
        result_decl = TREE_OPERAND (result_decl, 0);
 
       gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR
+                  || TREE_CODE (ret_expr) == GIMPLE_MODIFY_STMT
                   || TREE_CODE (ret_expr) == INIT_EXPR)
                  && TREE_CODE (result_decl) == RESULT_DECL);
     }
                   || TREE_CODE (ret_expr) == INIT_EXPR)
                  && TREE_CODE (result_decl) == RESULT_DECL);
     }
@@ -1167,6 +1181,9 @@ gimplify_return_expr (tree stmt, tree *pre_p)
   else
     {
       result = create_tmp_var (TREE_TYPE (result_decl), NULL);
   else
     {
       result = create_tmp_var (TREE_TYPE (result_decl), NULL);
+      if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
+          || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
+        DECL_GIMPLE_REG_P (result) = 1;
 
       /* ??? With complex control flow (usually involving abnormal edges),
         we can wind up warning about an uninitialized value for this.  Due
 
       /* ??? With complex control flow (usually involving abnormal edges),
         we can wind up warning about an uninitialized value for this.  Due
@@ -1177,10 +1194,10 @@ gimplify_return_expr (tree stmt, tree *pre_p)
       gimplify_ctxp->return_temp = result;
     }
 
       gimplify_ctxp->return_temp = result;
     }
 
-  /* Smash the lhs of the MODIFY_EXPR to the temporary we plan to use.
+  /* Smash the lhs of the GIMPLE_MODIFY_STMT to the temporary we plan to use.
      Then gimplify the whole thing.  */
   if (result != result_decl)
      Then gimplify the whole thing.  */
   if (result != result_decl)
-    TREE_OPERAND (ret_expr, 0) = result;
+    GENERIC_TREE_OPERAND (ret_expr, 0) = result;
 
   gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
 
 
   gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
 
@@ -1189,12 +1206,47 @@ gimplify_return_expr (tree stmt, tree *pre_p)
   if (result == result_decl)
     ret_expr = result;
   else
   if (result == result_decl)
     ret_expr = result;
   else
-    ret_expr = build2 (MODIFY_EXPR, TREE_TYPE (result), result_decl, result);
+    ret_expr = build_gimple_modify_stmt (result_decl, result);
   TREE_OPERAND (stmt, 0) = ret_expr;
 
   return GS_ALL_DONE;
 }
 
   TREE_OPERAND (stmt, 0) = ret_expr;
 
   return GS_ALL_DONE;
 }
 
+static void
+gimplify_vla_decl (tree decl, tree *stmt_p)
+{
+  /* This is a variable-sized decl.  Simplify its size and mark it
+     for deferred expansion.  Note that mudflap depends on the format
+     of the emitted code: see mx_register_decls().  */
+  tree t, addr, ptr_type;
+
+  gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
+  gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
+
+  /* All occurrences of this decl in final gimplified code will be
+     replaced by indirection.  Setting DECL_VALUE_EXPR does two
+     things: First, it lets the rest of the gimplifier know what
+     replacement to use.  Second, it lets the debug info know
+     where to find the value.  */
+  ptr_type = build_pointer_type (TREE_TYPE (decl));
+  addr = create_tmp_var (ptr_type, get_name (decl));
+  DECL_IGNORED_P (addr) = 0;
+  t = build_fold_indirect_ref (addr);
+  SET_DECL_VALUE_EXPR (decl, t);
+  DECL_HAS_VALUE_EXPR_P (decl) = 1;
+
+  t = built_in_decls[BUILT_IN_ALLOCA];
+  t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl));
+  t = fold_convert (ptr_type, t);
+  t = build_gimple_modify_stmt (addr, t);
+
+  gimplify_and_add (t, stmt_p);
+
+  /* Indicate that we need to restore the stack level when the
+     enclosing BIND_EXPR is exited.  */
+  gimplify_ctxp->save_stack = true;
+}
+
 /* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
 /* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
@@ -1219,39 +1271,7 @@ gimplify_decl_expr (tree *stmt_p)
       tree init = DECL_INITIAL (decl);
 
       if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
       tree init = DECL_INITIAL (decl);
 
       if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
-       {
-         /* This is a variable-sized decl.  Simplify its size and mark it
-            for deferred expansion.  Note that mudflap depends on the format
-            of the emitted code: see mx_register_decls().  */
-         tree t, args, addr, ptr_type;
-
-         gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
-         gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
-
-         /* All occurrences of this decl in final gimplified code will be
-            replaced by indirection.  Setting DECL_VALUE_EXPR does two
-            things: First, it lets the rest of the gimplifier know what
-            replacement to use.  Second, it lets the debug info know
-            where to find the value.  */
-         ptr_type = build_pointer_type (TREE_TYPE (decl));
-         addr = create_tmp_var (ptr_type, get_name (decl));
-         DECL_IGNORED_P (addr) = 0;
-         t = build_fold_indirect_ref (addr);
-         SET_DECL_VALUE_EXPR (decl, t);
-         DECL_HAS_VALUE_EXPR_P (decl) = 1;
-
-         args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL);
-         t = built_in_decls[BUILT_IN_ALLOCA];
-         t = build_function_call_expr (t, args);
-         t = fold_convert (ptr_type, t);
-         t = build2 (MODIFY_EXPR, void_type_node, addr, t);
-
-         gimplify_and_add (t, stmt_p);
-
-         /* Indicate that we need to restore the stack level when the
-            enclosing BIND_EXPR is exited.  */
-         gimplify_ctxp->save_stack = true;
-       }
+       gimplify_vla_decl (decl, stmt_p);
 
       if (init && init != error_mark_node)
        {
 
       if (init && init != error_mark_node)
        {
@@ -1316,8 +1336,8 @@ gimplify_loop_expr (tree *expr_p, tree *pre_p)
 static int
 compare_case_labels (const void *p1, const void *p2)
 {
 static int
 compare_case_labels (const void *p1, const void *p2)
 {
-  tree case1 = *(tree *)p1;
-  tree case2 = *(tree *)p2;
+  const_tree const case1 = *(const_tree const*)p1;
+  const_tree const case2 = *(const_tree const*)p2;
 
   return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
 }
 
   return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
 }
@@ -1394,7 +1414,7 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
            {
              /* Discard empty ranges.  */
              tree high = CASE_HIGH (elt);
            {
              /* Discard empty ranges.  */
              tree high = CASE_HIGH (elt);
-             if (high && INT_CST_LT (high, low))
+             if (high && tree_int_cst_lt (high, low))
                remove_element = TRUE;
            }
          else
                remove_element = TRUE;
            }
          else
@@ -1536,17 +1556,31 @@ canonicalize_component_ref (tree *expr_p)
   else
     type = TREE_TYPE (TREE_OPERAND (expr, 1));
 
   else
     type = TREE_TYPE (TREE_OPERAND (expr, 1));
 
+  /* One could argue that all the stuff below is not necessary for
+     the non-bitfield case and declare it a FE error if type
+     adjustment would be needed.  */
   if (TREE_TYPE (expr) != type)
     {
   if (TREE_TYPE (expr) != type)
     {
+#ifdef ENABLE_TYPES_CHECKING
       tree old_type = TREE_TYPE (expr);
       tree old_type = TREE_TYPE (expr);
+#endif
+      int type_quals;
+
+      /* We need to preserve qualifiers and propagate them from
+        operand 0.  */
+      type_quals = TYPE_QUALS (type)
+       | TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0)));
+      if (TYPE_QUALS (type) != type_quals)
+       type = build_qualified_type (TYPE_MAIN_VARIANT (type), type_quals);
 
       /* Set the type of the COMPONENT_REF to the underlying type.  */
       TREE_TYPE (expr) = type;
 
 
       /* Set the type of the COMPONENT_REF to the underlying type.  */
       TREE_TYPE (expr) = type;
 
-      /* And wrap the whole thing inside a NOP_EXPR.  */
-      expr = build1 (NOP_EXPR, old_type, expr);
-
-      *expr_p = expr;
+#ifdef ENABLE_TYPES_CHECKING
+      /* It is now a FE error, if the conversion from the canonical
+        type to the original expression type is not useless.  */
+      gcc_assert (useless_type_conversion_p (old_type, type));
+#endif
     }
 }
 
     }
 }
 
@@ -1557,52 +1591,46 @@ canonicalize_component_ref (tree *expr_p)
    ==>
       &array[L]
    where L is the lower bound.  For simplicity, only do this for constant
    ==>
       &array[L]
    where L is the lower bound.  For simplicity, only do this for constant
-   lower bound.  */
+   lower bound.
+   The constraint is that the type of &array[L] is trivially convertible
+   to T *.  */
 
 static void
 canonicalize_addr_expr (tree *expr_p)
 {
   tree expr = *expr_p;
 
 static void
 canonicalize_addr_expr (tree *expr_p)
 {
   tree expr = *expr_p;
-  tree ctype = TREE_TYPE (expr);
   tree addr_expr = TREE_OPERAND (expr, 0);
   tree addr_expr = TREE_OPERAND (expr, 0);
-  tree atype = TREE_TYPE (addr_expr);
-  tree dctype, datype, ddatype, otype, obj_expr;
+  tree datype, ddatype, pddatype;
 
 
-  /* Both cast and addr_expr types should be pointers.  */
-  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
+  /* We simplify only conversions from an ADDR_EXPR to a pointer type.  */
+  if (!POINTER_TYPE_P (TREE_TYPE (expr))
+      || TREE_CODE (addr_expr) != ADDR_EXPR)
     return;
 
   /* The addr_expr type should be a pointer to an array.  */
     return;
 
   /* The addr_expr type should be a pointer to an array.  */
-  datype = TREE_TYPE (atype);
+  datype = TREE_TYPE (TREE_TYPE (addr_expr));
   if (TREE_CODE (datype) != ARRAY_TYPE)
     return;
 
   if (TREE_CODE (datype) != ARRAY_TYPE)
     return;
 
-  /* Both cast and addr_expr types should address the same object type.  */
-  dctype = TREE_TYPE (ctype);
+  /* The pointer to element type shall be trivially convertible to
+     the expression pointer type.  */
   ddatype = TREE_TYPE (datype);
   ddatype = TREE_TYPE (datype);
-  if (!lang_hooks.types_compatible_p (ddatype, dctype))
-    return;
-
-  /* The addr_expr and the object type should match.  */
-  obj_expr = TREE_OPERAND (addr_expr, 0);
-  otype = TREE_TYPE (obj_expr);
-  if (!lang_hooks.types_compatible_p (otype, datype))
+  pddatype = build_pointer_type (ddatype);
+  if (!useless_type_conversion_p (pddatype, ddatype))
     return;
 
   /* The lower bound and element sizes must be constant.  */
     return;
 
   /* The lower bound and element sizes must be constant.  */
-  if (!TYPE_SIZE_UNIT (dctype)
-      || TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+  if (!TYPE_SIZE_UNIT (ddatype)
+      || TREE_CODE (TYPE_SIZE_UNIT (ddatype)) != INTEGER_CST
       || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
       || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
     return;
 
   /* All checks succeeded.  Build a new node to merge the cast.  */
       || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
       || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
     return;
 
   /* All checks succeeded.  Build a new node to merge the cast.  */
-  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
-                   TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+  *expr_p = build4 (ARRAY_REF, ddatype, TREE_OPERAND (addr_expr, 0),
                    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
                    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
-                   size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
-                               size_int (TYPE_ALIGN_UNIT (dctype))));
-  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
+                   NULL_TREE, NULL_TREE);
+  *expr_p = build1 (ADDR_EXPR, pddatype, *expr_p);
 }
 
 /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
 }
 
 /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
@@ -1611,6 +1639,7 @@ canonicalize_addr_expr (tree *expr_p)
 static enum gimplify_status
 gimplify_conversion (tree *expr_p)
 {
 static enum gimplify_status
 gimplify_conversion (tree *expr_p)
 {
+  tree tem;
   gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
              || TREE_CODE (*expr_p) == CONVERT_EXPR);
   
   gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
              || TREE_CODE (*expr_p) == CONVERT_EXPR);
   
@@ -1621,6 +1650,21 @@ gimplify_conversion (tree *expr_p)
   if (tree_ssa_useless_type_conversion (*expr_p))
     *expr_p = TREE_OPERAND (*expr_p, 0);
 
   if (tree_ssa_useless_type_conversion (*expr_p))
     *expr_p = TREE_OPERAND (*expr_p, 0);
 
+  /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
+     For example this fold (subclass *)&A into &A->subclass avoiding
+     a need for statement.  */
+  if (TREE_CODE (*expr_p) == NOP_EXPR
+      && POINTER_TYPE_P (TREE_TYPE (*expr_p))
+      && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
+      && (tem = maybe_fold_offset_to_reference
+                 (TREE_OPERAND (*expr_p, 0),
+                  integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p)))))
+    {
+      tree ptr_type = build_pointer_type (TREE_TYPE (tem));
+      if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
+        *expr_p = build_fold_addr_expr_with_type (tem, ptr_type);
+    }
+
   /* If we still have a conversion at the toplevel,
      then canonicalize some constructs.  */
   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
   /* If we still have a conversion at the toplevel,
      then canonicalize some constructs.  */
   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
@@ -1942,8 +1986,17 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
        return ret;
     }
 
        return ret;
     }
 
+  /* For POINTERs increment, use POINTER_PLUS_EXPR.  */
+  if (POINTER_TYPE_P (TREE_TYPE (lhs)))
+    {
+      rhs = fold_convert (sizetype, rhs);
+      if (arith_code == MINUS_EXPR)
+       rhs = fold_build1 (NEGATE_EXPR, TREE_TYPE (rhs), rhs);
+      arith_code = POINTER_PLUS_EXPR;
+    }
+
   t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
   t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
-  t1 = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
+  t1 = build_gimple_modify_stmt (lvalue, t1);
 
   if (postfix)
     {
 
   if (postfix)
     {
@@ -2020,9 +2073,9 @@ gimplify_arg (tree *expr_p, tree *pre_p)
 static enum gimplify_status
 gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
 {
 static enum gimplify_status
 gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
 {
-  tree decl;
-  tree arglist;
+  tree decl, parms, p;
   enum gimplify_status ret;
   enum gimplify_status ret;
+  int i, nargs;
 
   gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
 
 
   gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
 
@@ -2046,8 +2099,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   decl = get_callee_fndecl (*expr_p);
   if (decl && DECL_BUILT_IN (decl))
     {
   decl = get_callee_fndecl (*expr_p);
   if (decl && DECL_BUILT_IN (decl))
     {
-      tree arglist = TREE_OPERAND (*expr_p, 1);
-      tree new = fold_builtin (decl, arglist, !want_value);
+      tree new = fold_call_expr (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
 
       if (new && new != *expr_p)
        {
@@ -2061,62 +2113,152 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
       if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
          && 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)
         {
-         if (!arglist || !TREE_CHAIN (arglist))
+         if (call_expr_nargs (*expr_p) < 2)
            {
              error ("too few arguments to function %<va_start%>");
              *expr_p = build_empty_stmt ();
              return GS_OK;
            }
          
            {
              error ("too few arguments to function %<va_start%>");
              *expr_p = build_empty_stmt ();
              return GS_OK;
            }
          
-         if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
+         if (fold_builtin_next_arg (*expr_p, true))
            {
              *expr_p = build_empty_stmt ();
              return GS_OK;
            }
          /* Avoid gimplifying the second argument to va_start, which needs
             to be the plain PARM_DECL.  */
            {
              *expr_p = build_empty_stmt ();
              return GS_OK;
            }
          /* Avoid gimplifying the second argument to va_start, which needs
             to be the plain PARM_DECL.  */
-         return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
+         return gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p);
        }
     }
 
   /* There is a sequence point before the call, so any side effects in
      the calling expression must occur before the actual call.  Force
      gimplify_expr to use an internal post queue.  */
        }
     }
 
   /* There is a sequence point before the call, so any side effects in
      the calling expression must occur before the actual call.  Force
      gimplify_expr to use an internal post queue.  */
-  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
+  ret = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL,
                       is_gimple_call_addr, fb_rvalue);
 
                       is_gimple_call_addr, fb_rvalue);
 
-  if (PUSH_ARGS_REVERSED)
-    TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
-  for (arglist = TREE_OPERAND (*expr_p, 1); arglist;
-       arglist = TREE_CHAIN (arglist))
+  nargs = call_expr_nargs (*expr_p);
+
+  /* Get argument types for verification.  */
+  decl = get_callee_fndecl (*expr_p);
+  parms = NULL_TREE;
+  if (decl)
+    parms = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  else if (POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_FN (*expr_p))))
+    parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (*expr_p))));
+
+  /* Verify if the type of the argument matches that of the function
+     declaration.  If we cannot verify this or there is a mismatch,
+     mark the call expression so it doesn't get inlined later.  */
+  if (decl && DECL_ARGUMENTS (decl))
+    {
+      for (i = 0, p = DECL_ARGUMENTS (decl); i < nargs;
+          i++, p = TREE_CHAIN (p))
+       {
+         /* We cannot distinguish a varargs function from the case
+            of excess parameters, still deferring the inlining decision
+            to the callee is possible.  */
+         if (!p)
+           break;
+         if (p == error_mark_node
+             || CALL_EXPR_ARG (*expr_p, i) == error_mark_node
+             || !fold_convertible_p (DECL_ARG_TYPE (p),
+                                     CALL_EXPR_ARG (*expr_p, i)))
+           {
+             CALL_CANNOT_INLINE_P (*expr_p) = 1;
+             break;
+           }
+       }
+    }
+  else if (parms)
+    {
+      for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
+       {
+         /* If this is a varargs function defer inlining decision
+            to callee.  */
+         if (!p)
+           break;
+         if (TREE_VALUE (p) == error_mark_node
+             || CALL_EXPR_ARG (*expr_p, i) == error_mark_node
+             || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
+             || !fold_convertible_p (TREE_VALUE (p),
+                                     CALL_EXPR_ARG (*expr_p, i)))
+           {
+             CALL_CANNOT_INLINE_P (*expr_p) = 1;
+             break;
+           }
+       }
+    }
+  else
+    {
+      if (nargs != 0)
+       CALL_CANNOT_INLINE_P (*expr_p) = 1;
+      i = 0;
+      p = NULL_TREE;
+    }
+
+  /* If the last argument is __builtin_va_arg_pack () and it is not
+     passed as a named argument, decrease the number of CALL_EXPR
+     arguments and set instead the CALL_EXPR_VA_ARG_PACK flag.  */
+  if (!p
+      && i < nargs
+      && TREE_CODE (CALL_EXPR_ARG (*expr_p, nargs - 1)) == CALL_EXPR)
+    {
+      tree last_arg = CALL_EXPR_ARG (*expr_p, nargs - 1);
+      tree last_arg_fndecl = get_callee_fndecl (last_arg);
+
+      if (last_arg_fndecl
+         && TREE_CODE (last_arg_fndecl) == FUNCTION_DECL
+         && DECL_BUILT_IN_CLASS (last_arg_fndecl) == BUILT_IN_NORMAL
+         && DECL_FUNCTION_CODE (last_arg_fndecl) == BUILT_IN_VA_ARG_PACK)
+       {
+         tree call = *expr_p;
+
+         --nargs;
+         *expr_p = build_call_array (TREE_TYPE (call), CALL_EXPR_FN (call),
+                                     nargs, CALL_EXPR_ARGP (call));
+         /* Copy all CALL_EXPR flags, locus and block, except
+            CALL_EXPR_VA_ARG_PACK flag.  */
+         CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call);
+         CALL_EXPR_TAILCALL (*expr_p) = CALL_EXPR_TAILCALL (call);
+         CALL_EXPR_RETURN_SLOT_OPT (*expr_p)
+           = CALL_EXPR_RETURN_SLOT_OPT (call);
+         CALL_FROM_THUNK_P (*expr_p) = CALL_FROM_THUNK_P (call);
+         CALL_CANNOT_INLINE_P (*expr_p)
+           = CALL_CANNOT_INLINE_P (call);
+         TREE_NOTHROW (*expr_p) = TREE_NOTHROW (call);
+         SET_EXPR_LOCUS (*expr_p, EXPR_LOCUS (call));
+         TREE_BLOCK (*expr_p) = TREE_BLOCK (call);
+         /* Set CALL_EXPR_VA_ARG_PACK.  */
+         CALL_EXPR_VA_ARG_PACK (*expr_p) = 1;
+       }
+    }
+
+  /* Finally, gimplify the function arguments.  */
+  for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
+       PUSH_ARGS_REVERSED ? i >= 0 : i < nargs;
+       PUSH_ARGS_REVERSED ? i-- : i++)
     {
       enum gimplify_status t;
 
     {
       enum gimplify_status t;
 
-      t = gimplify_arg (&TREE_VALUE (arglist), pre_p);
+      t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p);
 
       if (t == GS_ERROR)
        ret = GS_ERROR;
     }
 
       if (t == GS_ERROR)
        ret = GS_ERROR;
     }
-  if (PUSH_ARGS_REVERSED)
-    TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
 
   /* Try this again in case gimplification exposed something.  */
   if (ret != GS_ERROR)
     {
 
   /* Try this again in case gimplification exposed something.  */
   if (ret != GS_ERROR)
     {
-      decl = get_callee_fndecl (*expr_p);
-      if (decl && DECL_BUILT_IN (decl))
-       {
-         tree arglist = TREE_OPERAND (*expr_p, 1);
-         tree new = fold_builtin (decl, arglist, !want_value);
+      tree new = fold_call_expr (*expr_p, !want_value);
 
 
-         if (new && new != *expr_p)
-           {
-             /* There was a transformation of this call which computes the
-                same value, but in a more efficient way.  Return and try
-                again.  */
-             *expr_p = new;
-             return GS_OK;
-           }
+      if (new && new != *expr_p)
+       {
+         /* There was a transformation of this call which computes the
+            same value, but in a more efficient way.  Return and try
+            again.  */
+         *expr_p = new;
+         return GS_OK;
        }
     }
 
        }
     }
 
@@ -2405,6 +2547,61 @@ gimple_boolify (tree expr)
     }
 }
 
     }
 }
 
+/* Given a conditional expression *EXPR_P without side effects, gimplify
+   its operands.  New statements are inserted to PRE_P.  */
+
+static enum gimplify_status
+gimplify_pure_cond_expr (tree *expr_p, tree *pre_p)
+{
+  tree expr = *expr_p, cond;
+  enum gimplify_status ret, tret;
+  enum tree_code code;
+
+  cond = gimple_boolify (COND_EXPR_COND (expr));
+
+  /* We need to handle && and || specially, as their gimplification
+     creates pure cond_expr, thus leading to an infinite cycle otherwise.  */
+  code = TREE_CODE (cond);
+  if (code == TRUTH_ANDIF_EXPR)
+    TREE_SET_CODE (cond, TRUTH_AND_EXPR);
+  else if (code == TRUTH_ORIF_EXPR)
+    TREE_SET_CODE (cond, TRUTH_OR_EXPR);
+  ret = gimplify_expr (&cond, pre_p, NULL,
+                             is_gimple_condexpr, fb_rvalue);
+  COND_EXPR_COND (*expr_p) = cond;
+
+  tret = gimplify_expr (&COND_EXPR_THEN (expr), pre_p, NULL,
+                                  is_gimple_val, fb_rvalue);
+  ret = MIN (ret, tret);
+  tret = gimplify_expr (&COND_EXPR_ELSE (expr), pre_p, NULL,
+                                  is_gimple_val, fb_rvalue);
+
+  return MIN (ret, tret);
+}
+
+/* Returns true if evaluating EXPR could trap.
+   EXPR is GENERIC, while tree_could_trap_p can be called
+   only on GIMPLE.  */
+
+static bool
+generic_expr_could_trap_p (tree expr)
+{
+  unsigned i, n;
+
+  if (!expr || is_gimple_val (expr))
+    return false;
+
+  if (!EXPR_P (expr) || tree_could_trap_p (expr))
+    return true;
+
+  n = TREE_OPERAND_LENGTH (expr);
+  for (i = 0; i < n; i++)
+    if (generic_expr_could_trap_p (TREE_OPERAND (expr, i)))
+      return true;
+
+  return false;
+}
+
 /*  Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;'
     into
 
 /*  Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;'
     into
 
@@ -2436,8 +2633,21 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
     {
       tree result;
 
     {
       tree result;
 
-      if ((fallback & fb_lvalue) == 0)
+      /* If an rvalue is ok or we do not require an lvalue, avoid creating
+        an addressable temporary.  */
+      if (((fallback & fb_rvalue)
+          || !(fallback & fb_lvalue))
+         && !TREE_ADDRESSABLE (type))
        {
        {
+         if (gimplify_ctxp->allow_rhs_cond_expr
+             /* If either branch has side effects or could trap, it can't be
+                evaluated unconditionally.  */
+             && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1))
+             && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 1))
+             && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 2))
+             && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 2)))
+           return gimplify_pure_cond_expr (expr_p, pre_p);
+
          result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
          ret = GS_ALL_DONE;
        }
          result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
          ret = GS_ALL_DONE;
        }
@@ -2452,7 +2662,7 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
          if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
            TREE_OPERAND (expr, 2) =
              build_fold_addr_expr (TREE_OPERAND (expr, 2));
          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 = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
          tmp2 = tmp = create_tmp_var (type, "iftmp");
 
          expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
@@ -2466,12 +2676,12 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
         if this branch is void; in C++ it can be, if it's a throw.  */
       if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
        TREE_OPERAND (expr, 1)
         if this branch is void; in C++ it can be, if it's a throw.  */
       if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
        TREE_OPERAND (expr, 1)
-         = build2 (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
+         = build_gimple_modify_stmt (tmp, TREE_OPERAND (expr, 1));
 
       /* Build the else clause, 't1 = b;'.  */
       if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
        TREE_OPERAND (expr, 2)
 
       /* Build the else clause, 't1 = b;'.  */
       if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
        TREE_OPERAND (expr, 2)
-         = build2 (MODIFY_EXPR, void_type_node, tmp2, TREE_OPERAND (expr, 2));
+         = build_gimple_modify_stmt (tmp2, TREE_OPERAND (expr, 2));
 
       TREE_TYPE (expr) = void_type_node;
       recalculate_side_effects (expr);
 
       TREE_TYPE (expr) = void_type_node;
       recalculate_side_effects (expr);
@@ -2549,20 +2759,16 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
 static enum gimplify_status
 gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
 {
 static enum gimplify_status
 gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
 {
-  tree args, t, to, to_ptr, from;
-
-  to = TREE_OPERAND (*expr_p, 0);
-  from = TREE_OPERAND (*expr_p, 1);
+  tree t, to, to_ptr, from, from_ptr;
 
 
-  args = tree_cons (NULL, size, NULL);
+  to = GENERIC_TREE_OPERAND (*expr_p, 0);
+  from = GENERIC_TREE_OPERAND (*expr_p, 1);
 
 
-  t = build_fold_addr_expr (from);
-  args = tree_cons (NULL, t, args);
+  from_ptr = build_fold_addr_expr (from);
 
   to_ptr = build_fold_addr_expr (to);
 
   to_ptr = build_fold_addr_expr (to);
-  args = tree_cons (NULL, to_ptr, args);
   t = implicit_built_in_decls[BUILT_IN_MEMCPY];
   t = implicit_built_in_decls[BUILT_IN_MEMCPY];
-  t = build_function_call_expr (t, args);
+  t = build_call_expr (t, 3, to_ptr, from_ptr, size);
 
   if (want_value)
     {
 
   if (want_value)
     {
@@ -2581,18 +2787,13 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
 static enum gimplify_status
 gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value)
 {
 static enum gimplify_status
 gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value)
 {
-  tree args, t, to, to_ptr;
+  tree t, to, to_ptr;
 
 
-  to = TREE_OPERAND (*expr_p, 0);
-
-  args = tree_cons (NULL, size, NULL);
-
-  args = tree_cons (NULL, integer_zero_node, args);
+  to = GENERIC_TREE_OPERAND (*expr_p, 0);
 
   to_ptr = build_fold_addr_expr (to);
 
   to_ptr = build_fold_addr_expr (to);
-  args = tree_cons (NULL, to_ptr, args);
   t = implicit_built_in_decls[BUILT_IN_MEMSET];
   t = implicit_built_in_decls[BUILT_IN_MEMSET];
-  t = build_function_call_expr (t, args);
+  t = build_call_expr (t, 3, to_ptr, integer_zero_node, size);
 
   if (want_value)
     {
 
   if (want_value)
     {
@@ -2615,7 +2816,7 @@ struct gimplify_init_ctor_preeval_data
   tree lhs_base_decl;
 
   /* The alias set of the lhs object.  */
   tree lhs_base_decl;
 
   /* The alias set of the lhs object.  */
-  int lhs_alias_set;
+  alias_set_type lhs_alias_set;
 };
 
 static tree
 };
 
 static tree
@@ -2637,6 +2838,21 @@ gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata)
       && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
     return t;
 
       && 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.  */
+  if (TREE_CODE (t) == CALL_EXPR)
+    {
+      tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t)));
+
+      for (type = TYPE_ARG_TYPES (fntype); type; type = TREE_CHAIN (type))
+       if (POINTER_TYPE_P (TREE_VALUE (type))
+           && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
+           && alias_sets_conflict_p (data->lhs_alias_set,
+                                     get_alias_set
+                                       (TREE_TYPE (TREE_VALUE (type)))))
+         return t;
+    }
+
   if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
   return NULL;
   if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
   return NULL;
@@ -2738,7 +2954,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
                               tree *pre_p, bool cleared)
 {
   tree loop_entry_label, loop_exit_label;
                               tree *pre_p, bool cleared)
 {
   tree loop_entry_label, loop_exit_label;
-  tree var, var_type, cref;
+  tree var, var_type, cref, tmp;
 
   loop_entry_label = create_artificial_label ();
   loop_exit_label = create_artificial_label ();
 
   loop_entry_label = create_artificial_label ();
   loop_exit_label = create_artificial_label ();
@@ -2746,7 +2962,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
   /* Create and initialize the index variable.  */
   var_type = TREE_TYPE (upper);
   var = create_tmp_var (var_type, NULL);
   /* Create and initialize the index variable.  */
   var_type = TREE_TYPE (upper);
   var = create_tmp_var (var_type, NULL);
-  append_to_statement_list (build2 (MODIFY_EXPR, var_type, var, lower), pre_p);
+  append_to_statement_list (build_gimple_modify_stmt (var, lower), pre_p);
 
   /* Add the loop entry label.  */
   append_to_statement_list (build1 (LABEL_EXPR,
 
   /* Add the loop entry label.  */
   append_to_statement_list (build1 (LABEL_EXPR,
@@ -2767,9 +2983,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
     gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
                             pre_p, cleared);
   else
     gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
                             pre_p, cleared);
   else
-    append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (cref),
-                                     cref, value),
-                             pre_p);
+    append_to_statement_list (build_gimple_modify_stmt (cref, value), pre_p);
 
   /* We exit the loop when the index var is equal to the upper bound.  */
   gimplify_and_add (build3 (COND_EXPR, void_type_node,
 
   /* We exit the loop when the index var is equal to the upper bound.  */
   gimplify_and_add (build3 (COND_EXPR, void_type_node,
@@ -2782,11 +2996,9 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
                    pre_p);
 
   /* Otherwise, increment the index var...  */
                    pre_p);
 
   /* Otherwise, increment the index var...  */
-  append_to_statement_list (build2 (MODIFY_EXPR, var_type, var,
-                                   build2 (PLUS_EXPR, var_type, var,
-                                           fold_convert (var_type,
-                                                         integer_one_node))),
-                           pre_p);
+  tmp = build2 (PLUS_EXPR, var_type, var,
+               fold_convert (var_type, integer_one_node));
+  append_to_statement_list (build_gimple_modify_stmt (var, tmp), pre_p);
 
   /* ...and jump back to the loop entry.  */
   append_to_statement_list (build1 (GOTO_EXPR,
 
   /* ...and jump back to the loop entry.  */
   append_to_statement_list (build1 (GOTO_EXPR,
@@ -2804,7 +3016,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
 /* Return true if FDECL is accessing a field that is zero sized.  */
    
 static bool
 /* Return true if FDECL is accessing a field that is zero sized.  */
    
 static bool
-zero_sized_field_decl (tree fdecl)
+zero_sized_field_decl (const_tree fdecl)
 {
   if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl) 
       && integer_zerop (DECL_SIZE (fdecl)))
 {
   if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl) 
       && integer_zerop (DECL_SIZE (fdecl)))
@@ -2815,7 +3027,7 @@ zero_sized_field_decl (tree fdecl)
 /* Return true if TYPE is zero sized.  */
    
 static bool
 /* Return true if TYPE is zero sized.  */
    
 static bool
-zero_sized_type (tree type)
+zero_sized_type (const_tree type)
 {
   if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type)
       && integer_zerop (TYPE_SIZE (type)))
 {
   if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type)
       && integer_zerop (TYPE_SIZE (type)))
@@ -2884,6 +3096,10 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
 
       if (array_elt_type)
        {
 
       if (array_elt_type)
        {
+         /* Do not use bitsizetype for ARRAY_REF indices.  */
+         if (TYPE_DOMAIN (TREE_TYPE (object)))
+           purpose = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))),
+                                   purpose);
          cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
                         purpose, NULL_TREE, NULL_TREE);
        }
          cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
                         purpose, NULL_TREE, NULL_TREE);
        }
@@ -2911,14 +3127,21 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
 
    Note that we still need to clear any elements that don't have explicit
    initializers, so if not all elements are initialized we keep the
 
    Note that we still need to clear any elements that don't have explicit
    initializers, so if not all elements are initialized we keep the
-   original MODIFY_EXPR, we just remove all of the constructor elements.  */
+   original MODIFY_EXPR, we just remove all of the constructor elements.
+
+   If NOTIFY_TEMP_CREATION is true, do not gimplify, just return
+   GS_ERROR if we would have to create a temporary when gimplifying
+   this constructor.  Otherwise, return GS_OK.
+
+   If NOTIFY_TEMP_CREATION is false, just do the gimplification.  */
 
 static enum gimplify_status
 gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
 static enum gimplify_status
 gimplify_init_constructor (tree *expr_p, tree *pre_p,
-                          tree *post_p, bool want_value)
+                          tree *post_p, bool want_value,
+                          bool notify_temp_creation)
 {
   tree object;
 {
   tree object;
-  tree ctor = TREE_OPERAND (*expr_p, 1);
+  tree ctor = GENERIC_TREE_OPERAND (*expr_p, 1);
   tree type = TREE_TYPE (ctor);
   enum gimplify_status ret;
   VEC(constructor_elt,gc) *elts;
   tree type = TREE_TYPE (ctor);
   enum gimplify_status ret;
   VEC(constructor_elt,gc) *elts;
@@ -2926,11 +3149,14 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
   if (TREE_CODE (ctor) != CONSTRUCTOR)
     return GS_UNHANDLED;
 
   if (TREE_CODE (ctor) != CONSTRUCTOR)
     return GS_UNHANDLED;
 
-  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                      is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
-    return ret;
-  object = TREE_OPERAND (*expr_p, 0);
+  if (!notify_temp_creation)
+    {
+      ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                          is_gimple_lvalue, fb_lvalue);
+      if (ret == GS_ERROR)
+       return ret;
+    }
+  object = GENERIC_TREE_OPERAND (*expr_p, 0);
 
   elts = CONSTRUCTOR_ELTS (ctor);
 
 
   elts = CONSTRUCTOR_ELTS (ctor);
 
@@ -2951,7 +3177,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
           individual elements.  The exception is that a CONSTRUCTOR node
           with no elements indicates zero-initialization of the whole.  */
        if (VEC_empty (constructor_elt, elts))
           individual elements.  The exception is that a CONSTRUCTOR node
           with no elements indicates zero-initialization of the whole.  */
        if (VEC_empty (constructor_elt, elts))
-         break;
+         {
+           if (notify_temp_creation)
+             return GS_OK;
+           break;
+         }
 
        /* Fetch information about the constructor to direct later processing.
           We might want to make static versions of it in various cases, and
 
        /* Fetch information about the constructor to direct later processing.
           We might want to make static versions of it in various cases, and
@@ -2967,6 +3197,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
            && TREE_READONLY (object)
            && TREE_CODE (object) == VAR_DECL)
          {
            && TREE_READONLY (object)
            && TREE_CODE (object) == VAR_DECL)
          {
+           if (notify_temp_creation)
+             return GS_ERROR;
            DECL_INITIAL (object) = ctor;
            TREE_STATIC (object) = 1;
            if (!DECL_NAME (object))
            DECL_INITIAL (object) = ctor;
            TREE_STATIC (object) = 1;
            if (!DECL_NAME (object))
@@ -3043,7 +3275,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
            if (size > 0 && !can_move_by_pieces (size, align))
              {
 
            if (size > 0 && !can_move_by_pieces (size, align))
              {
-               tree new = create_tmp_var_raw (type, "C");
+               tree new;
+
+               if (notify_temp_creation)
+                 return GS_ERROR;
+
+               new = create_tmp_var_raw (type, "C");
 
                gimple_add_tmp_var (new);
                TREE_STATIC (new) = 1;
 
                gimple_add_tmp_var (new);
                TREE_STATIC (new) = 1;
@@ -3056,7 +3293,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
                  }
                walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
 
                  }
                walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
 
-               TREE_OPERAND (*expr_p, 1) = new;
+               GENERIC_TREE_OPERAND (*expr_p, 1) = new;
 
                /* This is no longer an assignment of a CONSTRUCTOR, but
                   we still may have processing to do on the LHS.  So
 
                /* This is no longer an assignment of a CONSTRUCTOR, but
                   we still may have processing to do on the LHS.  So
@@ -3065,6 +3302,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
              }
          }
 
              }
          }
 
+       if (notify_temp_creation)
+         return GS_OK;
+
        /* If there are nonzero elements, pre-evaluate to capture elements
           overlapping with the lhs into temporaries.  We must do this before
           clearing to fetch the values before they are zeroed-out.  */
        /* If there are nonzero elements, pre-evaluate to capture elements
           overlapping with the lhs into temporaries.  We must do this before
           clearing to fetch the values before they are zeroed-out.  */
@@ -3075,7 +3315,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
              preeval_data.lhs_base_decl = NULL;
            preeval_data.lhs_alias_set = get_alias_set (object);
 
              preeval_data.lhs_base_decl = NULL;
            preeval_data.lhs_alias_set = get_alias_set (object);
 
-           gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
+           gimplify_init_ctor_preeval (&GENERIC_TREE_OPERAND (*expr_p, 1),
                                        pre_p, post_p, &preeval_data);
          }
 
                                        pre_p, post_p, &preeval_data);
          }
 
@@ -3104,6 +3344,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
       {
        tree r, i;
 
       {
        tree r, i;
 
+       if (notify_temp_creation)
+         return GS_OK;
+
        /* Extract the real and imaginary parts out of the ctor.  */
        gcc_assert (VEC_length (constructor_elt, elts) == 2);
        r = VEC_index (constructor_elt, elts, 0)->value;
        /* Extract the real and imaginary parts out of the ctor.  */
        gcc_assert (VEC_length (constructor_elt, elts) == 2);
        r = VEC_index (constructor_elt, elts, 0)->value;
@@ -3140,6 +3383,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
        unsigned HOST_WIDE_INT ix;
        constructor_elt *ce;
 
        unsigned HOST_WIDE_INT ix;
        constructor_elt *ce;
 
+       if (notify_temp_creation)
+         return GS_OK;
+
        /* Go ahead and simplify constant constructors to VECTOR_CST.  */
        if (TREE_CONSTANT (ctor))
          {
        /* Go ahead and simplify constant constructors to VECTOR_CST.  */
        if (TREE_CONSTANT (ctor))
          {
@@ -3147,8 +3393,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
            tree value;
 
            /* Even when ctor is constant, it might contain non-*_CST
            tree value;
 
            /* 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.  */
+              elements, such as addresses or trapping values like
+              1.0/0.0 - 1.0/0.0.  Such expressions don't belong
+              in VECTOR_CST nodes.  */
            FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
              if (!CONSTANT_CLASS_P (value))
                {
            FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
              if (!CONSTANT_CLASS_P (value))
                {
@@ -3162,10 +3409,14 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
                break;
              }
 
                break;
              }
 
-           /* Don't reduce a TREE_CONSTANT vector ctor even if we can't
+           /* Don't reduce an initializer constant even if we can't
               make a VECTOR_CST.  It won't do anything for us, and it'll
               prevent us from representing it as a single constant.  */
               make a VECTOR_CST.  It won't do anything for us, and it'll
               prevent us from representing it as a single constant.  */
-           break;
+           if (initializer_constant_valid_p (ctor, type))
+             break;
+
+           TREE_CONSTANT (ctor) = 0;
+           TREE_INVARIANT (ctor) = 0;
          }
 
        /* Vector types use CONSTRUCTOR all the way through gimple
          }
 
        /* Vector types use CONSTRUCTOR all the way through gimple
@@ -3178,6 +3429,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
            if (tret == GS_ERROR)
              ret = GS_ERROR;
          }
            if (tret == GS_ERROR)
              ret = GS_ERROR;
          }
+       if (!is_gimple_reg (GENERIC_TREE_OPERAND (*expr_p, 0)))
+         GENERIC_TREE_OPERAND (*expr_p, 1) = get_formal_tmp_var (ctor, pre_p);
       }
       break;
 
       }
       break;
 
@@ -3200,13 +3453,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
 /* Given a pointer value OP0, return a simplified version of an
    indirection through OP0, or NULL_TREE if no simplification is
 
 /* Given a pointer value OP0, return a simplified version of an
    indirection through OP0, or NULL_TREE if no simplification is
-   possible.  This may only be applied to a rhs of an expression.
-   Note that the resulting type may be different from the type pointed
-   to in the sense that it is still compatible from the langhooks
-   point of view. */
+   possible.  Note that the resulting type may be different from
+   the type pointed to in the sense that it is still compatible
+   from the langhooks point of view. */
 
 
-static tree
-fold_indirect_ref_rhs (tree t)
+tree
+gimple_fold_indirect_ref (tree t)
 {
   tree type = TREE_TYPE (TREE_TYPE (t));
   tree sub = t;
 {
   tree type = TREE_TYPE (TREE_TYPE (t));
   tree sub = t;
@@ -3222,11 +3474,12 @@ fold_indirect_ref_rhs (tree t)
       tree op = TREE_OPERAND (sub, 0);
       tree optype = TREE_TYPE (op);
       /* *&p => p */
       tree op = TREE_OPERAND (sub, 0);
       tree optype = TREE_TYPE (op);
       /* *&p => p */
-      if (lang_hooks.types_compatible_p (type, optype))
+      if (useless_type_conversion_p (type, optype))
         return op;
         return op;
+
       /* *(foo *)&fooarray => fooarray[0] */
       /* *(foo *)&fooarray => fooarray[0] */
-      else if (TREE_CODE (optype) == ARRAY_TYPE
-              && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+      if (TREE_CODE (optype) == ARRAY_TYPE
+         && useless_type_conversion_p (type, TREE_TYPE (optype)))
        {
          tree type_domain = TYPE_DOMAIN (optype);
          tree min_val = size_zero_node;
        {
          tree type_domain = TYPE_DOMAIN (optype);
          tree min_val = size_zero_node;
@@ -3238,12 +3491,12 @@ fold_indirect_ref_rhs (tree t)
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
-      && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+      && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype))))
     {
       tree type_domain;
       tree min_val = size_zero_node;
       tree osub = sub;
     {
       tree type_domain;
       tree min_val = size_zero_node;
       tree osub = sub;
-      sub = fold_indirect_ref_rhs (sub);
+      sub = gimple_fold_indirect_ref (sub);
       if (! sub)
        sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
       type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
       if (! sub)
        sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
       type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
@@ -3255,8 +3508,22 @@ fold_indirect_ref_rhs (tree t)
   return NULL_TREE;
 }
 
   return NULL_TREE;
 }
 
-/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
-   based on the code of the RHS.  We loop for as long as something changes.  */
+/* Given a pointer value OP0, return a simplified version of an
+   indirection through OP0, or NULL_TREE if no simplification is
+   possible.  This may only be applied to a rhs of an expression.
+   Note that the resulting type may be different from the type pointed
+   to in the sense that it is still compatible from the langhooks
+   point of view. */
+
+static tree
+gimple_fold_indirect_ref_rhs (tree t)
+{
+  return gimple_fold_indirect_ref (t);
+}
+
+/* Subroutine of gimplify_modify_expr to do simplifications of
+   MODIFY_EXPRs based on the code of the RHS.  We loop for as long as
+   something changes.  */
 
 static enum gimplify_status
 gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
 
 static enum gimplify_status
 gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
@@ -3267,6 +3534,35 @@ 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))
       {
   while (ret != GS_UNHANDLED)
     switch (TREE_CODE (*from_p))
       {
+      case VAR_DECL:
+       /* If we're assigning from a constant constructor, move the
+          constructor expression to the RHS of the MODIFY_EXPR.  */
+       if (DECL_INITIAL (*from_p)
+           && TYPE_READONLY (TREE_TYPE (*from_p))
+           && !TREE_THIS_VOLATILE (*from_p)
+           && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR)
+         {
+           tree old_from = *from_p;
+
+           /* Move the constructor into the RHS.  */
+           *from_p = unshare_expr (DECL_INITIAL (*from_p));
+
+           /* Let's see if gimplify_init_constructor will need to put
+              it in memory.  If so, revert the change.  */
+           ret = gimplify_init_constructor (expr_p, NULL, NULL, false, true);
+           if (ret == GS_ERROR)
+             {
+               *from_p = old_from;
+               /* Fall through.  */
+             }
+           else
+             {
+               ret = GS_OK;
+               break;
+             }
+         }
+       ret = GS_UNHANDLED;
+       break;
       case INDIRECT_REF:
        {
          /* If we have code like 
       case INDIRECT_REF:
        {
          /* If we have code like 
@@ -3278,7 +3574,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_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.  */
             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_rhs (TREE_OPERAND (*from_p, 0));
+         tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
          if (t)
            {
              *from_p = t;
          if (t)
            {
              *from_p = t;
@@ -3323,7 +3619,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
       case CONSTRUCTOR:
        /* If we're initializing from a CONSTRUCTOR, break this into
           individual MODIFY_EXPRs.  */
       case CONSTRUCTOR:
        /* 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);
+       return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
+                                         false);
 
       case COND_EXPR:
        /* If we're assigning to a non-register type, push the assignment
 
       case COND_EXPR:
        /* If we're assigning to a non-register type, push the assignment
@@ -3410,7 +3707,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
            if (use_target)
              {
                CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1;
            if (use_target)
              {
                CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1;
-               lang_hooks.mark_addressable (*to_p);
+               mark_addressable (*to_p);
              }
          }
 
              }
          }
 
@@ -3452,9 +3749,63 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
   return ret;
 }
 
   return ret;
 }
 
+/* Destructively convert the TREE pointer in TP into a gimple tuple if
+   appropriate.  */
+
+static void
+tree_to_gimple_tuple (tree *tp)
+{
+
+  switch (TREE_CODE (*tp))
+    {
+    case GIMPLE_MODIFY_STMT:
+      return;
+    case MODIFY_EXPR:
+      {
+        struct gimple_stmt *gs;
+       tree lhs = TREE_OPERAND (*tp, 0);
+       bool def_stmt_self_p = false;
+
+       if (TREE_CODE (lhs) == SSA_NAME)
+         {
+           if (SSA_NAME_DEF_STMT (lhs) == *tp)
+             def_stmt_self_p = true;
+         }
+
+        gs = &make_node (GIMPLE_MODIFY_STMT)->gstmt;
+        gs->base = (*tp)->base;
+        /* The set to base above overwrites the CODE.  */
+        TREE_SET_CODE ((tree) gs, GIMPLE_MODIFY_STMT);
+
+       SET_EXPR_LOCUS ((tree) gs, EXPR_LOCUS (*tp));
+        gs->operands[0] = TREE_OPERAND (*tp, 0);
+        gs->operands[1] = TREE_OPERAND (*tp, 1);
+        gs->block = TREE_BLOCK (*tp);
+        *tp = (tree)gs;
+
+       /* If we re-gimplify a set to an SSA_NAME, we must change the
+          SSA name's DEF_STMT link.  */
+       if (def_stmt_self_p)
+         SSA_NAME_DEF_STMT (GIMPLE_STMT_OPERAND (*tp, 0)) = *tp;
+
+        return;
+      }
+    default:
+      break;
+    }
+}
+
 /* Promote partial stores to COMPLEX variables to total stores.  *EXPR_P is
    a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
 /* Promote partial stores to COMPLEX variables to total stores.  *EXPR_P is
    a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
-   DECL_COMPLEX_GIMPLE_REG_P set.  */
+   DECL_GIMPLE_REG_P set.
+
+   IMPORTANT NOTE: This promotion is performed by introducing a load of the
+   other, unmodified part of the complex object just before the total store.
+   As a consequence, if the object is still uninitialized, an undefined value
+   will be loaded into a register, which may result in a spurious exception
+   if the register is floating-point and the value happens to be a signaling
+   NaN for example.  Then the fully-fledged complex operations lowering pass
+   followed by a DCE pass are necessary in order to fix things up.  */
 
 static enum gimplify_status
 gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
 
 static enum gimplify_status
 gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
@@ -3462,8 +3813,8 @@ gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
   enum tree_code code, ocode;
   tree lhs, rhs, new_rhs, other, realpart, imagpart;
 
   enum tree_code code, ocode;
   tree lhs, rhs, new_rhs, other, realpart, imagpart;
 
-  lhs = TREE_OPERAND (*expr_p, 0);
-  rhs = TREE_OPERAND (*expr_p, 1);
+  lhs = GENERIC_TREE_OPERAND (*expr_p, 0);
+  rhs = GENERIC_TREE_OPERAND (*expr_p, 1);
   code = TREE_CODE (lhs);
   lhs = TREE_OPERAND (lhs, 0);
 
   code = TREE_CODE (lhs);
   lhs = TREE_OPERAND (lhs, 0);
 
@@ -3479,11 +3830,13 @@ gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
   else
     new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart);
 
   else
     new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart);
 
-  TREE_OPERAND (*expr_p, 0) = lhs;
-  TREE_OPERAND (*expr_p, 1) = new_rhs;
+  GENERIC_TREE_OPERAND (*expr_p, 0) = lhs;
+  GENERIC_TREE_OPERAND (*expr_p, 1) = new_rhs;
 
   if (want_value)
     {
 
   if (want_value)
     {
+      tree_to_gimple_tuple (expr_p);
+
       append_to_statement_list (*expr_p, pre_p);
       *expr_p = rhs;
     }
       append_to_statement_list (*expr_p, pre_p);
       *expr_p = rhs;
     }
@@ -3509,15 +3862,24 @@ gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
 static enum gimplify_status
 gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
 {
 static enum gimplify_status
 gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
 {
-  tree *from_p = &TREE_OPERAND (*expr_p, 1);
-  tree *to_p = &TREE_OPERAND (*expr_p, 0);
+  tree *from_p = &GENERIC_TREE_OPERAND (*expr_p, 1);
+  tree *to_p = &GENERIC_TREE_OPERAND (*expr_p, 0);
   enum gimplify_status ret = GS_UNHANDLED;
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
   enum gimplify_status ret = GS_UNHANDLED;
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
+             || TREE_CODE (*expr_p) == GIMPLE_MODIFY_STMT
              || TREE_CODE (*expr_p) == INIT_EXPR);
 
              || TREE_CODE (*expr_p) == INIT_EXPR);
 
-  /* For zero sized types only gimplify the left hand side and right hand side
-     as statements and throw away the assignment.  */
+  /* See if any simplifications can be done based on what the RHS is.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+                                 want_value);
+  if (ret != GS_UNHANDLED)
+    return ret;
+
+  /* For zero sized types only gimplify the left hand side and right hand
+     side as statements and throw away the assignment.  Do this after
+     gimplify_modify_expr_rhs so we handle TARGET_EXPRs of addressable
+     types properly.  */
   if (zero_sized_type (TREE_TYPE (*from_p)))
     {
       gimplify_stmt (from_p);
   if (zero_sized_type (TREE_TYPE (*from_p)))
     {
       gimplify_stmt (from_p);
@@ -3528,12 +3890,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
       return GS_ALL_DONE;
     }
 
       return GS_ALL_DONE;
     }
 
-  /* See if any simplifications can be done based on what the RHS is.  */
-  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
-                                 want_value);
-  if (ret != GS_UNHANDLED)
-    return ret;
-
   /* If the value being copied is of variable width, compute the length
      of the copy into a WITH_SIZE_EXPR.   Note that we need to do this
      before gimplifying any of the operands so that we can resolve any
   /* If the value being copied is of variable width, compute the length
      of the copy into a WITH_SIZE_EXPR.   Note that we need to do this
      before gimplifying any of the operands so that we can resolve any
@@ -3590,8 +3946,23 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
       *to_p = make_ssa_name (*to_p, *expr_p);
     }
 
       *to_p = make_ssa_name (*to_p, *expr_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) && DECL_IGNORED_P (*from_p)
+      && DECL_P (*to_p) && !DECL_IGNORED_P (*to_p))
+    {
+      if (!DECL_NAME (*from_p) && DECL_NAME (*to_p))
+       DECL_NAME (*from_p)
+         = create_tmp_var_name (IDENTIFIER_POINTER (DECL_NAME (*to_p)));
+      DECL_DEBUG_EXPR_IS_FROM (*from_p) = 1;
+      SET_DECL_DEBUG_EXPR (*from_p, *to_p);
+    }
+
   if (want_value)
     {
   if (want_value)
     {
+      tree_to_gimple_tuple (expr_p);
+
       append_to_statement_list (*expr_p, pre_p);
       *expr_p = *to_p;
       return GS_OK;
       append_to_statement_list (*expr_p, pre_p);
       *expr_p = *to_p;
       return GS_OK;
@@ -3608,18 +3979,15 @@ gimplify_variable_sized_compare (tree *expr_p)
 {
   tree op0 = TREE_OPERAND (*expr_p, 0);
   tree op1 = TREE_OPERAND (*expr_p, 1);
 {
   tree op0 = TREE_OPERAND (*expr_p, 0);
   tree op1 = TREE_OPERAND (*expr_p, 1);
-  tree args, t, dest;
-
-  t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
-  t = unshare_expr (t);
-  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
-  args = tree_cons (NULL, t, NULL);
-  t = build_fold_addr_expr (op1);
-  args = tree_cons (NULL, t, args);
+  tree t, arg, dest, src;
+
+  arg = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+  arg = unshare_expr (arg);
+  arg = SUBSTITUTE_PLACEHOLDER_IN_EXPR (arg, op0);
+  src = build_fold_addr_expr (op1);
   dest = build_fold_addr_expr (op0);
   dest = build_fold_addr_expr (op0);
-  args = tree_cons (NULL, dest, args);
   t = implicit_built_in_decls[BUILT_IN_MEMCMP];
   t = implicit_built_in_decls[BUILT_IN_MEMCMP];
-  t = build_function_call_expr (t, args);
+  t = build_call_expr (t, 3, dest, src, arg);
   *expr_p
     = build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
 
   *expr_p
     = build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
 
@@ -3831,19 +4199,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
        tree t_expr = TREE_TYPE (expr);
        tree t_op00 = TREE_TYPE (op00);
 
        tree t_expr = TREE_TYPE (expr);
        tree t_op00 = TREE_TYPE (op00);
 
-        if (!lang_hooks.types_compatible_p (t_expr, t_op00))
-         {
-#ifdef ENABLE_CHECKING
-           tree t_op0 = TREE_TYPE (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)));
-#endif
-           op00 = fold_convert (TREE_TYPE (expr), op00);
-         }
+        if (!useless_type_conversion_p (t_expr, t_op00))
+         op00 = fold_convert (TREE_TYPE (expr), op00);
         *expr_p = op00;
         ret = GS_OK;
       }
         *expr_p = op00;
         ret = GS_OK;
       }
@@ -3872,6 +4229,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
         the address of a call that returns a struct; see
         gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
         the implied temporary explicit.  */
         the address of a call that returns a struct; see
         gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
         the implied temporary explicit.  */
+
+      /* Mark the RHS addressable.  */
       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
                           is_gimple_addressable, fb_either);
       if (ret != GS_ERROR)
       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
                           is_gimple_addressable, fb_either);
       if (ret != GS_ERROR)
@@ -3887,8 +4246,7 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
             is set properly.  */
          recompute_tree_invariant_for_addr_expr (expr);
 
             is set properly.  */
          recompute_tree_invariant_for_addr_expr (expr);
 
-         /* Mark the RHS addressable.  */
-         lang_hooks.mark_addressable (TREE_OPERAND (expr, 0));
+         mark_addressable (TREE_OPERAND (expr, 0));
        }
       break;
     }
        }
       break;
     }
@@ -3926,7 +4284,7 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
                               &allows_mem, &allows_reg, &is_inout);
 
       if (!allows_reg && allows_mem)
                               &allows_mem, &allows_reg, &is_inout);
 
       if (!allows_reg && allows_mem)
-       lang_hooks.mark_addressable (TREE_VALUE (link));
+       mark_addressable (TREE_VALUE (link));
 
       tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
                            is_inout ? is_gimple_min_lval : is_gimple_lvalue,
 
       tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
                            is_inout ? is_gimple_min_lval : is_gimple_lvalue,
@@ -4037,12 +4395,25 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
       parse_input_constraint (&constraint, 0, 0, noutputs, 0,
                              oconstraints, &allows_mem, &allows_reg);
 
       parse_input_constraint (&constraint, 0, 0, noutputs, 0,
                              oconstraints, &allows_mem, &allows_reg);
 
+      /* If we can't make copies, we can only accept memory.  */
+      if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (link))))
+       {
+         if (allows_mem)
+           allows_reg = 0;
+         else
+           {
+             error ("impossible constraint in %<asm%>");
+             error ("non-memory input %d must stay in memory", i);
+             return GS_ERROR;
+           }
+       }
+
       /* If the operand is a memory input, it should be an lvalue.  */
       if (!allows_reg && allows_mem)
        {
          tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
                                is_gimple_lvalue, fb_lvalue | fb_mayfail);
       /* If the operand is a memory input, it should be an lvalue.  */
       if (!allows_reg && allows_mem)
        {
          tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
                                is_gimple_lvalue, fb_lvalue | fb_mayfail);
-         lang_hooks.mark_addressable (TREE_VALUE (link));
+         mark_addressable (TREE_VALUE (link));
          if (tret == GS_ERROR)
            {
              error ("memory input %d is not directly addressable", i);
          if (tret == GS_ERROR)
            {
              error ("memory input %d is not directly addressable", i);
@@ -4182,10 +4553,8 @@ gimple_push_cleanup (tree var, tree cleanup, bool eh_only, tree *pre_p)
       */
 
       tree flag = create_tmp_var (boolean_type_node, "cleanup");
       */
 
       tree flag = create_tmp_var (boolean_type_node, "cleanup");
-      tree ffalse = build2 (MODIFY_EXPR, void_type_node, flag,
-                           boolean_false_node);
-      tree ftrue = build2 (MODIFY_EXPR, void_type_node, flag,
-                          boolean_true_node);
+      tree ffalse = build_gimple_modify_stmt (flag, boolean_false_node);
+      tree ftrue = build_gimple_modify_stmt (flag, boolean_true_node);
       cleanup = build3 (COND_EXPR, void_type_node, flag, cleanup, NULL);
       wce = build1 (WITH_CLEANUP_EXPR, void_type_node, cleanup);
       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
       cleanup = build3 (COND_EXPR, void_type_node, flag, cleanup, NULL);
       wce = build1 (WITH_CLEANUP_EXPR, void_type_node, cleanup);
       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
@@ -4220,8 +4589,15 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
   if (init)
     {
       /* TARGET_EXPR temps aren't part of the enclosing block, so add it
   if (init)
     {
       /* TARGET_EXPR temps aren't part of the enclosing block, so add it
-        to the temps list.  */
-      gimple_add_tmp_var (temp);
+        to the temps list.  Handle also variable length TARGET_EXPRs.  */
+      if (TREE_CODE (DECL_SIZE (temp)) != INTEGER_CST)
+       {
+         if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (temp)))
+           gimplify_type_sizes (TREE_TYPE (temp), pre_p);
+         gimplify_vla_decl (temp, pre_p);
+       }
+      else
+       gimple_add_tmp_var (temp);
 
       /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
         expression is supposed to initialize the slot.  */
 
       /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
         expression is supposed to initialize the slot.  */
@@ -4234,7 +4610,11 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
                               fb_none);
        }
       if (ret == GS_ERROR)
                               fb_none);
        }
       if (ret == GS_ERROR)
-       return GS_ERROR;
+       {
+         /* PR c++/28266 Make sure this is expanded only once. */
+         TARGET_EXPR_INITIAL (targ) = NULL_TREE;
+         return GS_ERROR;
+       }
       append_to_statement_list (init, pre_p);
 
       /* If needed, push the cleanup for the temp.  */
       append_to_statement_list (init, pre_p);
 
       /* If needed, push the cleanup for the temp.  */
@@ -4333,6 +4713,7 @@ omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type)
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case REAL_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
       omp_firstprivatize_variable (ctx, TYPE_MIN_VALUE (type));
       omp_firstprivatize_variable (ctx, TYPE_MAX_VALUE (type));
       break;
       omp_firstprivatize_variable (ctx, TYPE_MIN_VALUE (type));
       omp_firstprivatize_variable (ctx, TYPE_MAX_VALUE (type));
       break;
@@ -4439,8 +4820,11 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags)
       /* We're going to make use of the TYPE_SIZE_UNIT at least in the 
         alloca statement we generate for the variable, so make sure it
         is available.  This isn't automatically needed for the SHARED
       /* We're going to make use of the TYPE_SIZE_UNIT at least in the 
         alloca statement we generate for the variable, so make sure it
         is available.  This isn't automatically needed for the SHARED
-        case, since we won't be allocating local storage then.  */
-      else
+        case, since we won't be allocating local storage then.
+        For local variables TYPE_SIZE_UNIT might not be gimplified yet,
+        in this case omp_notice_variable will be called later
+        on when it is gimplified.  */
+      else if (! (flags & GOVD_LOCAL))
        omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true);
     }
   else if (lang_hooks.decls.omp_privatize_by_reference (decl))
        omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true);
     }
   else if (lang_hooks.decls.omp_privatize_by_reference (decl))
@@ -4598,6 +4982,31 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl)
     return !is_global_var (decl);
 }
 
     return !is_global_var (decl);
 }
 
+/* Return true if DECL is private within a parallel region
+   that binds to the current construct's context or in parallel
+   region's REDUCTION clause.  */
+
+static bool
+omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
+{
+  splay_tree_node n;
+
+  do
+    {
+      ctx = ctx->outer_context;
+      if (ctx == NULL)
+       return !(is_global_var (decl)
+                /* References might be private, but might be shared too.  */
+                || lang_hooks.decls.omp_privatize_by_reference (decl));
+
+      n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+      if (n != NULL)
+       return (n->value & GOVD_SHARED) == 0;
+    }
+  while (!ctx->is_parallel);
+  return false;
+}
+
 /* Scan the OpenMP clauses in *LIST_P, installing mappings into a new
    and previous omp contexts.  */
 
 /* Scan the OpenMP clauses in *LIST_P, installing mappings into a new
    and previous omp contexts.  */
 
@@ -4616,6 +5025,7 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
       enum gimplify_status gs;
       bool remove = false;
       bool notice_outer = true;
       enum gimplify_status gs;
       bool remove = false;
       bool notice_outer = true;
+      const char *check_non_private = NULL;
       unsigned int flags;
       tree decl;
 
       unsigned int flags;
       tree decl;
 
@@ -4630,12 +5040,15 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
          goto do_add;
        case OMP_CLAUSE_FIRSTPRIVATE:
          flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT;
          goto do_add;
        case OMP_CLAUSE_FIRSTPRIVATE:
          flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT;
+         check_non_private = "firstprivate";
          goto do_add;
        case OMP_CLAUSE_LASTPRIVATE:
          flags = GOVD_LASTPRIVATE | GOVD_SEEN | GOVD_EXPLICIT;
          goto do_add;
        case OMP_CLAUSE_LASTPRIVATE:
          flags = GOVD_LASTPRIVATE | GOVD_SEEN | GOVD_EXPLICIT;
+         check_non_private = "lastprivate";
          goto do_add;
        case OMP_CLAUSE_REDUCTION:
          flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT;
          goto do_add;
        case OMP_CLAUSE_REDUCTION:
          flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT;
+         check_non_private = "reduction";
          goto do_add;
 
        do_add:
          goto do_add;
 
        do_add:
@@ -4645,11 +5058,6 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
              remove = true;
              break;
            }
              remove = true;
              break;
            }
-         /* Handle NRV results passed by reference.  */
-         if (TREE_CODE (decl) == INDIRECT_REF
-             && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
-             && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
-           OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
          omp_add_variable (ctx, decl, flags);
          if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
              && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
          omp_add_variable (ctx, decl, flags);
          if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
              && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@@ -4677,14 +5085,17 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
              remove = true;
              break;
            }
              remove = true;
              break;
            }
-         /* Handle NRV results passed by reference.  */
-         if (TREE_CODE (decl) == INDIRECT_REF
-             && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
-             && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
-           OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
        do_notice:
          if (outer_ctx)
            omp_notice_variable (outer_ctx, decl, true);
        do_notice:
          if (outer_ctx)
            omp_notice_variable (outer_ctx, decl, true);
+         if (check_non_private
+             && !in_parallel
+             && omp_check_private (ctx, decl))
+           {
+             error ("%s variable %qs is private in outer context",
+                    check_non_private, IDENTIFIER_POINTER (DECL_NAME (decl)));
+             remove = true;
+           }
          break;
 
        case OMP_CLAUSE_IF:
          break;
 
        case OMP_CLAUSE_IF:
@@ -4752,7 +5163,20 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
   else if (flags & GOVD_SHARED)
     {
       if (is_global_var (decl))
   else if (flags & GOVD_SHARED)
     {
       if (is_global_var (decl))
-       return 0;
+       {
+         struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context;
+         while (ctx != NULL)
+           {
+             splay_tree_node on
+               = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+             if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE
+                                     | GOVD_PRIVATE | GOVD_REDUCTION)) != 0)
+               break;
+             ctx = ctx->outer_context;
+           }
+         if (ctx == NULL)
+           return 0;
+       }
       code = OMP_CLAUSE_SHARED;
     }
   else if (flags & GOVD_PRIVATE)
       code = OMP_CLAUSE_SHARED;
     }
   else if (flags & GOVD_PRIVATE)
@@ -4875,16 +5299,18 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
 static enum gimplify_status
 gimplify_omp_for (tree *expr_p, tree *pre_p)
 {
 static enum gimplify_status
 gimplify_omp_for (tree *expr_p, tree *pre_p)
 {
-  tree for_stmt, decl, t;
+  tree for_stmt, decl, var, t;
   enum gimplify_status ret = GS_OK;
   enum gimplify_status ret = GS_OK;
+  tree body, init_decl = NULL_TREE;
 
   for_stmt = *expr_p;
 
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
 
   t = OMP_FOR_INIT (for_stmt);
 
   for_stmt = *expr_p;
 
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
 
   t = OMP_FOR_INIT (for_stmt);
-  gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
-  decl = TREE_OPERAND (t, 0);
+  gcc_assert (TREE_CODE (t) == MODIFY_EXPR
+             || TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+  decl = GENERIC_TREE_OPERAND (t, 0);
   gcc_assert (DECL_P (decl));
   gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)));
 
   gcc_assert (DECL_P (decl));
   gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)));
 
@@ -4894,47 +5320,78 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
   else
     omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
 
   else
     omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
 
-  ret |= gimplify_expr (&TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt),
+  /* If DECL is not a gimple register, create a temporary variable to act as an
+     iteration counter.  This is valid, since DECL cannot be modified in the
+     body of the loop.  */
+  if (!is_gimple_reg (decl))
+    {
+      var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
+      GENERIC_TREE_OPERAND (t, 0) = var;
+
+      init_decl = build_gimple_modify_stmt (decl, var);
+      omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+    }
+  else
+    var = decl;
+
+  /* If OMP_FOR is re-gimplified, ensure all variables in pre-body
+     are noticed.  */
+  gimplify_stmt (&OMP_FOR_PRE_BODY (for_stmt));
+
+  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                       &OMP_FOR_PRE_BODY (for_stmt),
                        NULL, is_gimple_val, fb_rvalue);
 
                        NULL, is_gimple_val, fb_rvalue);
 
+  tree_to_gimple_tuple (&OMP_FOR_INIT (for_stmt));
+
   t = OMP_FOR_COND (for_stmt);
   gcc_assert (COMPARISON_CLASS_P (t));
   t = OMP_FOR_COND (for_stmt);
   gcc_assert (COMPARISON_CLASS_P (t));
-  gcc_assert (TREE_OPERAND (t, 0) == decl);
+  gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
+  TREE_OPERAND (t, 0) = var;
 
 
-  ret |= gimplify_expr (&TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt),
+  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                       &OMP_FOR_PRE_BODY (for_stmt),
                        NULL, is_gimple_val, fb_rvalue);
 
                        NULL, is_gimple_val, fb_rvalue);
 
+  tree_to_gimple_tuple (&OMP_FOR_INCR (for_stmt));
   t = OMP_FOR_INCR (for_stmt);
   switch (TREE_CODE (t))
     {
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
       t = build_int_cst (TREE_TYPE (decl), 1);
   t = OMP_FOR_INCR (for_stmt);
   switch (TREE_CODE (t))
     {
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
       t = build_int_cst (TREE_TYPE (decl), 1);
-      goto build_modify;
+      t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+      t = build_gimple_modify_stmt (var, t);
+      OMP_FOR_INCR (for_stmt) = t;
+      break;
+
     case PREDECREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       t = build_int_cst (TREE_TYPE (decl), -1);
     case PREDECREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       t = build_int_cst (TREE_TYPE (decl), -1);
-      goto build_modify;
-    build_modify:
-      t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
-      t = build2 (MODIFY_EXPR, void_type_node, decl, t);
+      t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+      t = build_gimple_modify_stmt (var, t);
       OMP_FOR_INCR (for_stmt) = t;
       break;
       
       OMP_FOR_INCR (for_stmt) = t;
       break;
       
-    case MODIFY_EXPR:
-      gcc_assert (TREE_OPERAND (t, 0) == decl);
-      t = TREE_OPERAND (t, 1);
+    case GIMPLE_MODIFY_STMT:
+      gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
+      GIMPLE_STMT_OPERAND (t, 0) = var;
+
+      t = GIMPLE_STMT_OPERAND (t, 1);
       switch (TREE_CODE (t))
        {
        case PLUS_EXPR:
          if (TREE_OPERAND (t, 1) == decl)
            {
              TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
       switch (TREE_CODE (t))
        {
        case PLUS_EXPR:
          if (TREE_OPERAND (t, 1) == decl)
            {
              TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
-             TREE_OPERAND (t, 0) = decl;
+             TREE_OPERAND (t, 0) = var;
              break;
            }
              break;
            }
+
+         /* Fallthru.  */
        case MINUS_EXPR:
          gcc_assert (TREE_OPERAND (t, 0) == decl);
        case MINUS_EXPR:
          gcc_assert (TREE_OPERAND (t, 0) == decl);
+         TREE_OPERAND (t, 0) = var;
          break;
        default:
          gcc_unreachable ();
          break;
        default:
          gcc_unreachable ();
@@ -4948,7 +5405,13 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
       gcc_unreachable ();
     }
 
       gcc_unreachable ();
     }
 
-  gimplify_to_stmt_list (&OMP_FOR_BODY (for_stmt));
+  body = OMP_FOR_BODY (for_stmt);
+  gimplify_to_stmt_list (&body);
+  t = alloc_stmt_list ();
+  if (init_decl)
+    append_to_statement_list (init_decl, &t);
+  append_to_statement_list (body, &t);
+  OMP_FOR_BODY (for_stmt) = t;
   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
 
   return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
 
   return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
@@ -4987,74 +5450,28 @@ goa_lhs_expr_p (tree expr, tree addr)
              == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (expr, 0)))))
     expr = TREE_OPERAND (expr, 0);
 
              == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (expr, 0)))))
     expr = TREE_OPERAND (expr, 0);
 
-  if (TREE_CODE (expr) == INDIRECT_REF && TREE_OPERAND (expr, 0) == addr)
-    return true;
+  if (TREE_CODE (expr) == INDIRECT_REF)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      while (expr != addr
+            && (TREE_CODE (expr) == NOP_EXPR
+                || TREE_CODE (expr) == CONVERT_EXPR
+                || TREE_CODE (expr) == NON_LVALUE_EXPR)
+            && TREE_CODE (expr) == TREE_CODE (addr)
+            && TYPE_MAIN_VARIANT (TREE_TYPE (expr))
+               == TYPE_MAIN_VARIANT (TREE_TYPE (addr)))
+       {
+         expr = TREE_OPERAND (expr, 0);
+         addr = TREE_OPERAND (addr, 0);
+       }
+      return expr == addr;
+    }
   if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0))
     return true;
   return false;
 }
 
   if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0))
     return true;
   return false;
 }
 
-/* A subroutine of gimplify_omp_atomic.  Attempt to implement the atomic
-   operation as a __sync_fetch_and_op builtin.  INDEX is log2 of the
-   size of the data type, and thus usable to find the index of the builtin
-   decl.  Returns GS_UNHANDLED if the expression is not of the proper form.  */
-
-static enum gimplify_status
-gimplify_omp_atomic_fetch_op (tree *expr_p, tree addr, tree rhs, int index)
-{
-  enum built_in_function base;
-  tree decl, args, itype;
-  enum insn_code *optab;
-
-  /* Check for one of the supported fetch-op operations.  */
-  switch (TREE_CODE (rhs))
-    {
-    case PLUS_EXPR:
-      base = BUILT_IN_FETCH_AND_ADD_N;
-      optab = sync_add_optab;
-      break;
-    case MINUS_EXPR:
-      base = BUILT_IN_FETCH_AND_SUB_N;
-      optab = sync_add_optab;
-      break;
-    case BIT_AND_EXPR:
-      base = BUILT_IN_FETCH_AND_AND_N;
-      optab = sync_and_optab;
-      break;
-    case BIT_IOR_EXPR:
-      base = BUILT_IN_FETCH_AND_OR_N;
-      optab = sync_ior_optab;
-      break;
-    case BIT_XOR_EXPR:
-      base = BUILT_IN_FETCH_AND_XOR_N;
-      optab = sync_xor_optab;
-      break;
-    default:
-      return GS_UNHANDLED;
-    }
-
-  /* Make sure the expression is of the proper form.  */
-  if (goa_lhs_expr_p (TREE_OPERAND (rhs, 0), addr))
-    rhs = TREE_OPERAND (rhs, 1);
-  else if (commutative_tree_code (TREE_CODE (rhs))
-          && goa_lhs_expr_p (TREE_OPERAND (rhs, 1), addr))
-    rhs = TREE_OPERAND (rhs, 0);
-  else
-    return GS_UNHANDLED;
-
-  decl = built_in_decls[base + index + 1];
-  itype = TREE_TYPE (TREE_TYPE (decl));
-
-  if (optab[TYPE_MODE (itype)] == CODE_FOR_nothing)
-    return GS_UNHANDLED;
-
-  args = tree_cons (NULL, fold_convert (itype, rhs), NULL);
-  args = tree_cons (NULL, addr, args);
-  *expr_p = build_function_call_expr (decl, args);
-  return GS_OK;
-}
-
-/* A subroutine of gimplify_omp_atomic_pipeline.  Walk *EXPR_P and replace
+/* Walk *EXPR_P and replace
    appearances of *LHS_ADDR with LHS_VAR.  If an expression does not involve
    the lhs, evaluate it into a temporary.  Return 1 if the lhs appeared as
    a subexpression, 0 if it did not, or -1 if an error was encountered.  */
    appearances of *LHS_ADDR with LHS_VAR.  If an expression does not involve
    the lhs, evaluate it into a temporary.  Return 1 if the lhs appeared as
    a subexpression, 0 if it did not, or -1 if an error was encountered.  */
@@ -5098,146 +5515,6 @@ goa_stabilize_expr (tree *expr_p, tree *pre_p, tree lhs_addr, tree lhs_var)
   return saw_lhs;
 }
 
   return saw_lhs;
 }
 
-/* A subroutine of gimplify_omp_atomic.  Implement the atomic operation as:
-
-       oldval = *addr;
-      repeat:
-       newval = rhs;   // with oldval replacing *addr in rhs
-       oldval = __sync_val_compare_and_swap (addr, oldval, newval);
-       if (oldval != newval)
-         goto repeat;
-
-   INDEX is log2 of the size of the data type, and thus usable to find the
-   index of the builtin decl.  */
-
-static enum gimplify_status
-gimplify_omp_atomic_pipeline (tree *expr_p, tree *pre_p, tree addr,
-                             tree rhs, int index)
-{
-  tree oldval, oldival, oldival2, newval, newival, label;
-  tree type, itype, cmpxchg, args, x, iaddr;
-
-  cmpxchg = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N + index + 1];
-  type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
-  itype = TREE_TYPE (TREE_TYPE (cmpxchg));
-
-  if (sync_compare_and_swap[TYPE_MODE (itype)] == CODE_FOR_nothing)
-    return GS_UNHANDLED;
-
-  oldval = create_tmp_var (type, NULL);
-  newval = create_tmp_var (type, NULL);
-
-  /* Precompute as much of RHS as possible.  In the same walk, replace
-     occurrences of the lhs value with our temporary.  */
-  if (goa_stabilize_expr (&rhs, pre_p, addr, oldval) < 0)
-    return GS_ERROR;
-
-  x = build_fold_indirect_ref (addr);
-  x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
-  gimplify_and_add (x, pre_p);
-
-  /* For floating-point values, we'll need to view-convert them to integers
-     so that we can perform the atomic compare and swap.  Simplify the 
-     following code by always setting up the "i"ntegral variables.  */
-  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
-    {
-      oldival = oldval;
-      newival = newval;
-      iaddr = addr;
-    }
-  else
-    {
-      oldival = create_tmp_var (itype, NULL);
-      newival = create_tmp_var (itype, NULL);
-
-      x = build1 (VIEW_CONVERT_EXPR, itype, oldval);
-      x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
-      gimplify_and_add (x, pre_p);
-      iaddr = fold_convert (build_pointer_type (itype), addr);
-    }
-
-  oldival2 = create_tmp_var (itype, NULL);
-
-  label = create_artificial_label ();
-  x = build1 (LABEL_EXPR, void_type_node, label);
-  gimplify_and_add (x, pre_p);
-
-  x = build2 (MODIFY_EXPR, void_type_node, newval, rhs);
-  gimplify_and_add (x, pre_p);
-
-  if (newval != newival)
-    {
-      x = build1 (VIEW_CONVERT_EXPR, itype, newval);
-      x = build2 (MODIFY_EXPR, void_type_node, newival, x);
-      gimplify_and_add (x, pre_p);
-    }
-
-  x = build2 (MODIFY_EXPR, void_type_node, oldival2,
-             fold_convert (itype, oldival));
-  gimplify_and_add (x, pre_p);
-
-  args = tree_cons (NULL, fold_convert (itype, newival), NULL);
-  args = tree_cons (NULL, fold_convert (itype, oldival), args);
-  args = tree_cons (NULL, iaddr, args);
-  x = build_function_call_expr (cmpxchg, args);
-  if (oldval == oldival)
-    x = fold_convert (type, x);
-  x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
-  gimplify_and_add (x, pre_p);
-
-  /* For floating point, be prepared for the loop backedge.  */
-  if (oldval != oldival)
-    {
-      x = build1 (VIEW_CONVERT_EXPR, type, oldival);
-      x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
-      gimplify_and_add (x, pre_p);
-    }
-
-  /* Note that we always perform the comparison as an integer, even for
-     floating point.  This allows the atomic operation to properly 
-     succeed even with NaNs and -0.0.  */
-  x = build3 (COND_EXPR, void_type_node,
-             build2 (NE_EXPR, boolean_type_node, oldival, oldival2),
-             build1 (GOTO_EXPR, void_type_node, label), NULL);
-  gimplify_and_add (x, pre_p);
-
-  *expr_p = NULL;
-  return GS_ALL_DONE;
-}
-
-/* A subroutine of gimplify_omp_atomic.  Implement the atomic operation as:
-
-       GOMP_atomic_start ();
-       *addr = rhs;
-       GOMP_atomic_end ();
-
-   The result is not globally atomic, but works so long as all parallel
-   references are within #pragma omp atomic directives.  According to
-   responses received from omp@openmp.org, appears to be within spec.
-   Which makes sense, since that's how several other compilers handle
-   this situation as well.  */
-
-static enum gimplify_status
-gimplify_omp_atomic_mutex (tree *expr_p, tree *pre_p, tree addr, tree rhs)
-{
-  tree t;
-
-  t = built_in_decls[BUILT_IN_GOMP_ATOMIC_START];
-  t = build_function_call_expr (t, NULL);
-  gimplify_and_add (t, pre_p);
-
-  t = build_fold_indirect_ref (addr);
-  t = build2 (MODIFY_EXPR, void_type_node, t, rhs);
-  gimplify_and_add (t, pre_p);
-  
-  t = built_in_decls[BUILT_IN_GOMP_ATOMIC_END];
-  t = build_function_call_expr (t, NULL);
-  gimplify_and_add (t, pre_p);
-
-  *expr_p = NULL;
-  return GS_ALL_DONE;
-}
-
 /* Gimplify an OMP_ATOMIC statement.  */
 
 static enum gimplify_status
 /* Gimplify an OMP_ATOMIC statement.  */
 
 static enum gimplify_status
@@ -5246,46 +5523,26 @@ gimplify_omp_atomic (tree *expr_p, tree *pre_p)
   tree addr = TREE_OPERAND (*expr_p, 0);
   tree rhs = TREE_OPERAND (*expr_p, 1);
   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
   tree addr = TREE_OPERAND (*expr_p, 0);
   tree rhs = TREE_OPERAND (*expr_p, 1);
   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
-  HOST_WIDE_INT index;
+  tree tmp_load, load, store;
 
 
-  /* Make sure the type is one of the supported sizes.  */
-  index = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-  index = exact_log2 (index);
-  if (index >= 0 && index <= 4)
-    {
-      enum gimplify_status gs;
-      unsigned int align;
-
-      if (DECL_P (TREE_OPERAND (addr, 0)))
-       align = DECL_ALIGN_UNIT (TREE_OPERAND (addr, 0));
-      else if (TREE_CODE (TREE_OPERAND (addr, 0)) == COMPONENT_REF
-              && TREE_CODE (TREE_OPERAND (TREE_OPERAND (addr, 0), 1))
-                 == FIELD_DECL)
-       align = DECL_ALIGN_UNIT (TREE_OPERAND (TREE_OPERAND (addr, 0), 1));
-      else
-       align = TYPE_ALIGN_UNIT (type);
+   tmp_load = create_tmp_var (type, NULL);
+   if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
+     return GS_ERROR;
 
 
-      /* __sync builtins require strict data alignment.  */
-      if (exact_log2 (align) >= index)
-       {
-         /* When possible, use specialized atomic update functions.  */
-         if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
-           {
-             gs = gimplify_omp_atomic_fetch_op (expr_p, addr, rhs, index);
-             if (gs != GS_UNHANDLED)
-               return gs;
-           }
+   if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
+       != GS_ALL_DONE)
+     return GS_ERROR;
 
 
-         /* If we don't have specialized __sync builtins, try and implement
-            as a compare and swap loop.  */
-         gs = gimplify_omp_atomic_pipeline (expr_p, pre_p, addr, rhs, index);
-         if (gs != GS_UNHANDLED)
-           return gs;
-       }
-    }
+   load = build2 (OMP_ATOMIC_LOAD, void_type_node, tmp_load, addr);
+   append_to_statement_list (load, pre_p);
+   if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
+       != GS_ALL_DONE)
+     return GS_ERROR;
+   store = build1 (OMP_ATOMIC_STORE, void_type_node, rhs);
+   *expr_p = store;
+
+   return GS_ALL_DONE;
 
 
-  /* The ultimate fallback is wrapping the operation in a mutex.  */
-  return gimplify_omp_atomic_mutex (expr_p, pre_p, addr, rhs);
 }
 
 /*  Gimplifies the expression tree pointed to by EXPR_P.  Return 0 if
 }
 
 /*  Gimplifies the expression tree pointed to by EXPR_P.  Return 0 if
@@ -5362,7 +5619,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
       /* Die, die, die, my darling.  */
       if (save_expr == error_mark_node
 
       /* Die, die, die, my darling.  */
       if (save_expr == error_mark_node
-         || (TREE_TYPE (save_expr)
+         || (!GIMPLE_STMT_P (save_expr)
+             && TREE_TYPE (save_expr)
              && TREE_TYPE (save_expr) == error_mark_node))
        {
          ret = GS_ERROR;
              && TREE_TYPE (save_expr) == error_mark_node))
        {
          ret = GS_ERROR;
@@ -5413,7 +5671,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
          if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
-             lang_hooks.mark_addressable (*expr_p);
+             mark_addressable (*expr_p);
            }
          break;
 
            }
          break;
 
@@ -5426,7 +5684,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
          if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
-             lang_hooks.mark_addressable (*expr_p);
+             mark_addressable (*expr_p);
            }
          break;
 
            }
          break;
 
@@ -5438,14 +5696,23 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case MODIFY_EXPR:
          break;
 
        case MODIFY_EXPR:
+       case GIMPLE_MODIFY_STMT:
        case INIT_EXPR:
          ret = gimplify_modify_expr (expr_p, pre_p, post_p,
                                      fallback != fb_none);
 
        case INIT_EXPR:
          ret = gimplify_modify_expr (expr_p, pre_p, post_p,
                                      fallback != fb_none);
 
-         /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer
-            useful.  */
-         if (*expr_p && TREE_CODE (*expr_p) == INIT_EXPR)
-           TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+         if (*expr_p)
+           {
+             /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer
+                useful.  */
+             if (TREE_CODE (*expr_p) == INIT_EXPR)
+               TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+
+             /* Convert MODIFY_EXPR to GIMPLE_MODIFY_STMT.  */
+             if (TREE_CODE (*expr_p) == MODIFY_EXPR)
+               tree_to_gimple_tuple (expr_p);
+           }
+
          break;
 
        case TRUTH_ANDIF_EXPR:
          break;
 
        case TRUTH_ANDIF_EXPR:
@@ -5515,6 +5782,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          /* Constants need not be gimplified.  */
        case INTEGER_CST:
        case REAL_CST:
          /* Constants need not be gimplified.  */
        case INTEGER_CST:
        case REAL_CST:
+       case FIXED_CST:
        case STRING_CST:
        case COMPLEX_CST:
        case VECTOR_CST:
        case STRING_CST:
        case COMPLEX_CST:
        case VECTOR_CST:
@@ -5605,7 +5873,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          else if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
          else if (fallback == fb_lvalue)
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
-             lang_hooks.mark_addressable (*expr_p);
+             mark_addressable (*expr_p);
            }
          else
            ret = GS_ALL_DONE;
            }
          else
            ret = GS_ALL_DONE;
@@ -5669,6 +5937,11 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = GS_ALL_DONE;
          break;
 
          ret = GS_ALL_DONE;
          break;
 
+       case CHANGE_DYNAMIC_TYPE_EXPR:
+         ret = gimplify_expr (&CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p),
+                              pre_p, post_p, is_gimple_reg, fb_lvalue);
+         break;
+
        case OBJ_TYPE_REF:
          {
            enum gimplify_status r0, r1;
        case OBJ_TYPE_REF:
          {
            enum gimplify_status r0, r1;
@@ -5745,9 +6018,45 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
        case OMP_RETURN:
        case OMP_CONTINUE:
 
        case OMP_RETURN:
        case OMP_CONTINUE:
+        case OMP_ATOMIC_LOAD:
+        case OMP_ATOMIC_STORE:
+
          ret = GS_ALL_DONE;
          break;
 
          ret = GS_ALL_DONE;
          break;
 
+       case POINTER_PLUS_EXPR:
+          /* Convert ((type *)A)+offset into &A->field_of_type_and_offset.
+            The second is gimple immediate saving a need for extra statement.
+          */
+         if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
+             && (tmp = maybe_fold_offset_to_reference
+                        (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
+                         TREE_TYPE (TREE_TYPE (*expr_p)))))
+            {
+              tree ptr_type = build_pointer_type (TREE_TYPE (tmp));
+              if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
+                {
+                   *expr_p = build_fold_addr_expr_with_type (tmp, ptr_type);
+                  break;
+                }
+            }
+         /* Convert (void *)&a + 4 into (void *)&a[1].  */
+         if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
+             && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
+             && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
+                                                                       0),0)))
+             && (tmp = maybe_fold_offset_to_reference
+                        (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
+                         TREE_OPERAND (*expr_p, 1),
+                         TREE_TYPE (TREE_TYPE
+                                 (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
+                                                0))))))
+            {
+               tmp = build_fold_addr_expr (tmp);
+               *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
+              break;
+            }
+          /* FALLTHRU */
        default:
          switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
            {
        default:
          switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
            {
@@ -5854,7 +6163,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
                             gimple_test_f, fallback);
              break;
 
                             gimple_test_f, fallback);
              break;
 
-           case ARRAY_REF: case ARRAY_RANGE_REF:
+           case ARRAY_REF:
+           case ARRAY_RANGE_REF:
              gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                             gimple_test_f, fallback);
              gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
              gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                             gimple_test_f, fallback);
              gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
@@ -5863,16 +6173,17 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
            default:
               /* Anything else with side-effects must be converted to
 
            default:
               /* Anything else with side-effects must be converted to
-                 a valid statement before we get here.  */
+                 a valid statement before we get here.  */
              gcc_unreachable ();
            }
 
          *expr_p = NULL;
        }
              gcc_unreachable ();
            }
 
          *expr_p = NULL;
        }
-      else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
+      else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p))
+              && TYPE_MODE (TREE_TYPE (*expr_p)) != BLKmode)
        {
        {
-         /* Historically, the compiler has treated a bare
-            reference to a volatile lvalue as forcing a load.  */
+         /* Historically, the compiler has treated a bare reference
+            to a non-BLKmode volatile lvalue as forcing a load.  */
          tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
          /* Normally, we do not want to create a temporary for a
             TREE_ADDRESSABLE type because such a type should not be
          tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
          /* Normally, we do not want to create a temporary for a
             TREE_ADDRESSABLE type because such a type should not be
@@ -5883,11 +6194,14 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
             given a TREE_ADDRESSABLE type.  */
          tree tmp = create_tmp_var_raw (type, "vol");
          gimple_add_tmp_var (tmp);
             given a TREE_ADDRESSABLE type.  */
          tree tmp = create_tmp_var_raw (type, "vol");
          gimple_add_tmp_var (tmp);
-         *expr_p = build2 (MODIFY_EXPR, type, tmp, *expr_p);
+         *expr_p = build_gimple_modify_stmt (tmp, *expr_p);
        }
       else
        /* We can't do anything useful with a volatile reference to
        }
       else
        /* We can't do anything useful with a volatile reference to
-          incomplete type, so just throw it away.  */
+          an incomplete type, so just throw it away.  Likewise for
+          a BLKmode type, since any implicit inner load should
+          already have been turned into an explicit one by the
+          gimplification process.  */
        *expr_p = NULL;
     }
 
        *expr_p = NULL;
     }
 
@@ -6015,6 +6329,7 @@ gimplify_type_sizes (tree type, tree *list_p)
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case REAL_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
       gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p);
       gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p);
 
       gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p);
       gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p);
 
@@ -6112,7 +6427,7 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
 
       *expr_p = create_tmp_var (type, NULL);
       tmp = build1 (NOP_EXPR, type, expr);
 
       *expr_p = create_tmp_var (type, NULL);
       tmp = build1 (NOP_EXPR, type, expr);
-      tmp = build2 (MODIFY_EXPR, type, *expr_p, tmp);
+      tmp = build_gimple_modify_stmt (*expr_p, tmp);
       if (EXPR_HAS_LOCATION (expr))
        SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr));
       else
       if (EXPR_HAS_LOCATION (expr))
        SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr));
       else
@@ -6122,84 +6437,6 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
     }
 }
 \f
     }
 }
 \f
-#ifdef ENABLE_CHECKING
-/* Compare types A and B for a "close enough" match.  */
-
-static bool
-cpt_same_type (tree a, tree b)
-{
-  if (lang_hooks.types_compatible_p (a, b))
-    return true;
-
-  /* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't
-     link them together.  This routine is intended to catch type errors
-     that will affect the optimizers, and the optimizers don't add new
-     dereferences of function pointers, so ignore it.  */
-  if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE)
-      && (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE))
-    return true;
-
-  /* ??? The C FE pushes type qualifiers after the fact into the type of
-     the element from the type of the array.  See build_unary_op's handling
-     of ADDR_EXPR.  This seems wrong -- if we were going to do this, we
-     should have done it when creating the variable in the first place.
-     Alternately, why aren't the two array types made variants?  */
-  if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE)
-    return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
-  /* And because of those, we have to recurse down through pointers.  */
-  if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b))
-    return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
-  return false;
-}
-
-/* Check for some cases of the front end missing cast expressions.
-   The type of a dereference should correspond to the pointer type;
-   similarly the type of an address should match its object.  */
-
-static tree
-check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  tree t = *tp;
-  tree ptype, otype, dtype;
-
-  switch (TREE_CODE (t))
-    {
-    case INDIRECT_REF:
-    case ARRAY_REF:
-      otype = TREE_TYPE (t);
-      ptype = TREE_TYPE (TREE_OPERAND (t, 0));
-      dtype = TREE_TYPE (ptype);
-      gcc_assert (cpt_same_type (otype, dtype));
-      break;
-
-    case ADDR_EXPR:
-      ptype = TREE_TYPE (t);
-      otype = TREE_TYPE (TREE_OPERAND (t, 0));
-      dtype = TREE_TYPE (ptype);
-      if (!cpt_same_type (otype, dtype))
-       {
-         /* &array is allowed to produce a pointer to the element, rather than
-            a pointer to the array type.  We must allow this in order to
-            properly represent assigning the address of an array in C into
-            pointer to the element type.  */
-         gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
-                     && POINTER_TYPE_P (ptype)
-                     && cpt_same_type (TREE_TYPE (otype), dtype));
-         break;
-       }
-      break;
-
-    default:
-      return NULL_TREE;
-    }
-
-
-  return NULL_TREE;
-}
-#endif
 
 /* Gimplify the body of statements pointed to by BODY_P.  FNDECL is the
    function decl containing BODY.  */
 
 /* Gimplify the body of statements pointed to by BODY_P.  FNDECL is the
    function decl containing BODY.  */
@@ -6268,8 +6505,9 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
   pop_gimplify_context (body);
   gcc_assert (gimplify_ctxp == NULL);
 
   pop_gimplify_context (body);
   gcc_assert (gimplify_ctxp == NULL);
 
-#ifdef ENABLE_CHECKING
-  walk_tree (body_p, check_pointer_types_r, NULL, NULL);
+#ifdef ENABLE_TYPES_CHECKING
+  if (!errorcount && !sorrycount)
+    verify_gimple_1 (BIND_EXPR_BODY (*body_p));
 #endif
 
   timevar_pop (TV_TREE_GIMPLIFY);
 #endif
 
   timevar_pop (TV_TREE_GIMPLIFY);
@@ -6286,25 +6524,28 @@ gimplify_function_tree (tree fndecl)
 
   oldfn = current_function_decl;
   current_function_decl = fndecl;
 
   oldfn = current_function_decl;
   current_function_decl = fndecl;
-  cfun = DECL_STRUCT_FUNCTION (fndecl);
-  if (cfun == NULL)
-    allocate_struct_function (fndecl);
+  if (DECL_STRUCT_FUNCTION (fndecl))
+    push_cfun (DECL_STRUCT_FUNCTION (fndecl));
+  else
+    push_struct_function (fndecl);
 
   for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
     {
       /* Preliminarily mark non-addressed complex variables as eligible
          for promotion to gimple registers.  We'll transform their uses
          as we find them.  */
 
   for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
     {
       /* Preliminarily mark non-addressed complex variables as eligible
          for promotion to gimple registers.  We'll transform their uses
          as we find them.  */
-      if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+      if ((TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+          || TREE_CODE (TREE_TYPE (parm)) == VECTOR_TYPE)
           && !TREE_THIS_VOLATILE (parm)
           && !needs_to_live_in_memory (parm))
           && !TREE_THIS_VOLATILE (parm)
           && !needs_to_live_in_memory (parm))
-        DECL_COMPLEX_GIMPLE_REG_P (parm) = 1;
+        DECL_GIMPLE_REG_P (parm) = 1;
     }
 
   ret = DECL_RESULT (fndecl);
     }
 
   ret = DECL_RESULT (fndecl);
-  if (TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
+  if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
+       || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
       && !needs_to_live_in_memory (ret))
       && !needs_to_live_in_memory (ret))
-    DECL_COMPLEX_GIMPLE_REG_P (ret) = 1;
+    DECL_GIMPLE_REG_P (ret) = 1;
 
   gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true);
 
 
   gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true);
 
@@ -6313,7 +6554,8 @@ gimplify_function_tree (tree fndecl)
      catch the exit hook.  */
   /* ??? Add some way to ignore exceptions for this TFE.  */
   if (flag_instrument_function_entry_exit
      catch the exit hook.  */
   /* ??? Add some way to ignore exceptions for this TFE.  */
   if (flag_instrument_function_entry_exit
-      && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl))
+      && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
+      && !flag_instrument_functions_exclude_p (fndecl))
     {
       tree tf, x, bind;
 
     {
       tree tf, x, bind;
 
@@ -6322,23 +6564,23 @@ gimplify_function_tree (tree fndecl)
       x = DECL_SAVED_TREE (fndecl);
       append_to_statement_list (x, &TREE_OPERAND (tf, 0));
       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT];
       x = DECL_SAVED_TREE (fndecl);
       append_to_statement_list (x, &TREE_OPERAND (tf, 0));
       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT];
-      x = build_function_call_expr (x, NULL);
+      x = build_call_expr (x, 0);
       append_to_statement_list (x, &TREE_OPERAND (tf, 1));
 
       bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
       TREE_SIDE_EFFECTS (bind) = 1;
       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER];
       append_to_statement_list (x, &TREE_OPERAND (tf, 1));
 
       bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
       TREE_SIDE_EFFECTS (bind) = 1;
       x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER];
-      x = build_function_call_expr (x, NULL);
+      x = build_call_expr (x, 0);
       append_to_statement_list (x, &BIND_EXPR_BODY (bind));
       append_to_statement_list (tf, &BIND_EXPR_BODY (bind));
 
       DECL_SAVED_TREE (fndecl) = bind;
     }
 
       append_to_statement_list (x, &BIND_EXPR_BODY (bind));
       append_to_statement_list (tf, &BIND_EXPR_BODY (bind));
 
       DECL_SAVED_TREE (fndecl) = bind;
     }
 
+  cfun->gimplified = true;
   current_function_decl = oldfn;
   current_function_decl = oldfn;
-  cfun = oldfn ? DECL_STRUCT_FUNCTION (oldfn) : NULL;
+  pop_cfun ();
 }
 }
-
 \f
 /* Expands EXPR to list of gimple statements STMTS.  If SIMPLE is true,
    force the result to be either ssa_name or an invariant, otherwise
 \f
 /* Expands EXPR to list of gimple statements STMTS.  If SIMPLE is true,
    force the result to be either ssa_name or an invariant, otherwise
@@ -6360,16 +6602,26 @@ 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 ();
   gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
 
   push_gimplify_context ();
-  gimplify_ctxp->into_ssa = in_ssa_p;
+  gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
+  gimplify_ctxp->allow_rhs_cond_expr = true;
 
   if (var)
 
   if (var)
-    expr = build2 (MODIFY_EXPR, TREE_TYPE (var), var, expr);
+    expr = build_gimple_modify_stmt (var, expr);
 
 
-  ret = gimplify_expr (&expr, stmts, NULL,
-                      gimple_test_f, fb_rvalue);
-  gcc_assert (ret != GS_ERROR);
+  if (TREE_CODE (expr) != GIMPLE_MODIFY_STMT
+      && TREE_TYPE (expr) == void_type_node)
+    {
+      gimplify_and_add (expr, stmts);
+      expr = NULL_TREE;
+    }
+  else
+    {
+      ret = gimplify_expr (&expr, stmts, NULL,
+                          gimple_test_f, fb_rvalue);
+      gcc_assert (ret != GS_ERROR);
+    }
 
 
-  if (referenced_vars)
+  if (gimple_referenced_vars (cfun))
     {
       for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
        add_referenced_var (t);
     {
       for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
        add_referenced_var (t);
@@ -6381,17 +6633,34 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
 }
 
 /* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR.  If
 }
 
 /* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR.  If
-   some statements are produced, emits them before BSI.  */
+   some statements are produced, emits them at BSI.  If BEFORE is true.
+   the statements are appended before BSI, otherwise they are appended after
+   it.  M specifies the way BSI moves after insertion (BSI_SAME_STMT or
+   BSI_CONTINUE_LINKING are the usual values).  */
 
 tree
 force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
 
 tree
 force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
-                         bool simple_p, tree var)
+                         bool simple_p, tree var, bool before,
+                         enum bsi_iterator_update m)
 {
   tree stmts;
 
   expr = force_gimple_operand (expr, &stmts, simple_p, var);
   if (stmts)
 {
   tree stmts;
 
   expr = force_gimple_operand (expr, &stmts, simple_p, var);
   if (stmts)
-    bsi_insert_before (bsi, stmts, BSI_SAME_STMT);
+    {
+      if (gimple_in_ssa_p (cfun))
+       {
+         tree_stmt_iterator tsi;
+
+         for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
+           mark_symbols_for_renaming (tsi_stmt (tsi));
+       }
+
+      if (before)
+       bsi_insert_before (bsi, stmts, m);
+      else
+       bsi_insert_after (bsi, stmts, m);
+    }
 
   return expr;
 }
 
   return expr;
 }