OSDN Git Service

2008-06-08 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 5c11bad..47a2fe7 100644 (file)
@@ -1,6 +1,6 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   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>.
@@ -62,10 +62,19 @@ enum gimplify_omp_var_data
   GOVD_REDUCTION = 64,
   GOVD_LOCAL = 128,
   GOVD_DEBUG_PRIVATE = 256,
+  GOVD_PRIVATE_OUTER_REF = 512,
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
                           | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL)
 };
 
+enum omp_region_type
+{
+  ORT_WORKSHARE = 0,
+  ORT_TASK = 1,
+  ORT_PARALLEL = 2,
+  ORT_COMBINED_PARALLEL = 3
+};
+
 struct gimplify_omp_ctx
 {
   struct gimplify_omp_ctx *outer_context;
@@ -73,8 +82,7 @@ struct gimplify_omp_ctx
   struct pointer_set_t *privatized_types;
   location_t location;
   enum omp_clause_default_kind default_kind;
-  bool is_parallel;
-  bool is_combined_parallel;
+  enum omp_region_type region_type;
 };
 
 struct gimplify_ctx
@@ -94,6 +102,7 @@ struct gimplify_ctx
   int conditions;
   bool save_stack;
   bool into_ssa;
+  bool allow_rhs_cond_expr;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -174,7 +183,7 @@ push_gimplify_context (void)
 
 /* Tear down a context for the gimplifier.  If BODY is non-null, then
    put the temporaries into the outer BIND_EXPR.  Otherwise, put them
-   in the unexpanded_var_list.  */
+   in the local_decls.  */
 
 void
 pop_gimplify_context (tree body)
@@ -269,7 +278,7 @@ splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb)
 /* Create a new omp construct that deals with variable remapping.  */
 
 static struct gimplify_omp_ctx *
-new_omp_context (bool is_parallel, bool is_combined_parallel)
+new_omp_context (enum omp_region_type region_type)
 {
   struct gimplify_omp_ctx *c;
 
@@ -278,9 +287,11 @@ new_omp_context (bool is_parallel, bool is_combined_parallel)
   c->variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0);
   c->privatized_types = pointer_set_create ();
   c->location = input_location;
-  c->is_parallel = is_parallel;
-  c->is_combined_parallel = is_combined_parallel;
-  c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  c->region_type = region_type;
+  if (region_type != ORT_TASK)
+    c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
+  else
+    c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
 
   return c;
 }
@@ -390,6 +401,13 @@ find_single_pointer_decl_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
 {
   tree *pdecl = (tree *) data;
 
+  /* We are only looking for pointers at the same level as the
+     original tree; we must not look through any indirections.
+     Returning anything other than NULL_TREE will cause the caller to
+     not find a base.  */
+  if (REFERENCE_CLASS_P (*tp))
+    return *tp;
+
   if (DECL_P (*tp) && POINTER_TYPE_P (TREE_TYPE (*tp)))
     {
       if (*pdecl)
@@ -405,8 +423,9 @@ find_single_pointer_decl_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   return NULL_TREE;
 }
 
-/* Find the single DECL of pointer type in the tree T and return it.
-   If there are zero or more than one such DECLs, return NULL.  */
+/* Find the single DECL of pointer type in the tree T, used directly
+   rather than via an indirection, and return it.  If there are zero
+   or more than one such DECLs, return NULL.  */
 
 static tree
 find_single_pointer_decl (tree t)
@@ -417,7 +436,8 @@ find_single_pointer_decl (tree t)
     {
       /* find_single_pointer_decl_1 returns a nonzero value, causing
         walk_tree to return a nonzero value, to indicate that it
-        found more than one pointer DECL.  */
+        found more than one pointer DECL or that it found an
+        indirection.  */
       return NULL_TREE;
     }
 
@@ -746,7 +766,7 @@ gimple_add_tmp_var (tree tmp)
       if (gimplify_omp_ctxp)
        {
          struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
-         while (ctx && !ctx->is_parallel)
+         while (ctx && ctx->region_type == ORT_WORKSHARE)
            ctx = ctx->outer_context;
          if (ctx)
            omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN);
@@ -1413,7 +1433,7 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
            {
              /* 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
@@ -1639,8 +1659,7 @@ 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 (CONVERT_EXPR_P (*expr_p));
   
   /* Then strip away all but the outermost conversion.  */
   STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
@@ -1666,7 +1685,7 @@ gimplify_conversion (tree *expr_p)
 
   /* 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 (CONVERT_EXPR_P (*expr_p))
     {
       tree sub = TREE_OPERAND (*expr_p, 0);
 
@@ -2264,10 +2283,14 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
      decl.  This allows us to eliminate redundant or useless
      calls to "const" functions.  */
-  if (TREE_CODE (*expr_p) == CALL_EXPR
-      && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
-    TREE_SIDE_EFFECTS (*expr_p) = 0;
-
+  if (TREE_CODE (*expr_p) == CALL_EXPR)
+    {
+      int flags = call_expr_flags (*expr_p);
+      if (flags & (ECF_CONST | ECF_PURE)
+         /* An infinite loop is considered a side effect.  */
+         && !(flags & (ECF_LOOPING_CONST_OR_PURE)))
+       TREE_SIDE_EFFECTS (*expr_p) = 0;
+    }
   return ret;
 }
 
@@ -2546,6 +2569,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
 
@@ -2577,8 +2655,21 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
     {
       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;
        }
@@ -2593,7 +2684,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));
-         
+
          tmp2 = tmp = create_tmp_var (type, "iftmp");
 
          expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
@@ -2799,12 +2890,14 @@ gimplify_init_ctor_preeval (tree *expr_p, tree *pre_p, tree *post_p,
 {
   enum gimplify_status one;
 
-  /* If the value is invariant, then there's nothing to pre-evaluate.
-     But ensure it doesn't have any side-effects since a SAVE_EXPR is
-     invariant but has side effects and might contain a reference to
-     the object we're initializing.  */
-  if (TREE_INVARIANT (*expr_p) && !TREE_SIDE_EFFECTS (*expr_p))
-    return;
+  /* If the value is constant, then there's nothing to pre-evaluate.  */
+  if (TREE_CONSTANT (*expr_p))
+    {
+      /* Ensure it does not have side effects, it might contain a reference to
+        the object we're initializing.  */
+      gcc_assert (!TREE_SIDE_EFFECTS (*expr_p));
+      return;
+    }
 
   /* If the type has non-trivial constructors, we can't pre-evaluate.  */
   if (TREE_ADDRESSABLE (TREE_TYPE (*expr_p)))
@@ -3027,6 +3120,10 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
 
       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);
        }
@@ -3054,11 +3151,18 @@ 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
-   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,
-                          tree *post_p, bool want_value)
+                          tree *post_p, bool want_value,
+                          bool notify_temp_creation)
 {
   tree object;
   tree ctor = GENERIC_TREE_OPERAND (*expr_p, 1);
@@ -3069,10 +3173,13 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
   if (TREE_CODE (ctor) != CONSTRUCTOR)
     return GS_UNHANDLED;
 
-  ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                      is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
-    return ret;
+  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);
@@ -3094,7 +3201,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))
-         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
@@ -3110,6 +3221,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
            && 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))
@@ -3186,7 +3299,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
            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;
@@ -3208,6 +3326,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.  */
@@ -3247,6 +3368,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
       {
        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;
@@ -3283,6 +3407,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
        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))
          {
@@ -3313,7 +3440,6 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
              break;
 
            TREE_CONSTANT (ctor) = 0;
-           TREE_INVARIANT (ctor) = 0;
          }
 
        /* Vector types use CONSTRUCTOR all the way through gimple
@@ -3350,13 +3476,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
-   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;
@@ -3374,9 +3499,10 @@ fold_indirect_ref_rhs (tree t)
       /* *&p => p */
       if (useless_type_conversion_p (type, optype))
         return op;
+
       /* *(foo *)&fooarray => fooarray[0] */
-      else if (TREE_CODE (optype) == ARRAY_TYPE
-              && useless_type_conversion_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;
@@ -3393,7 +3519,7 @@ fold_indirect_ref_rhs (tree t)
       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));
@@ -3405,8 +3531,22 @@ fold_indirect_ref_rhs (tree t)
   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,
@@ -3417,6 +3557,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))
       {
+      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 
@@ -3428,7 +3597,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.  */
-         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;
@@ -3453,7 +3622,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
             references somehow.  */
          tree init = TARGET_EXPR_INITIAL (*from_p);
 
-         if (!VOID_TYPE_P (TREE_TYPE (init)))
+         if (init
+             && !VOID_TYPE_P (TREE_TYPE (init)))
            {
              *from_p = init;
              ret = GS_OK;
@@ -3473,7 +3643,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.  */
-       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
@@ -3488,7 +3659,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
            tree result = *to_p;
 
            ret = gimplify_expr (&result, pre_p, post_p,
-                                is_gimple_min_lval, fb_lvalue);
+                                is_gimple_lvalue, fb_lvalue);
            if (ret != GS_ERROR)
              ret = GS_OK;
 
@@ -3650,7 +3821,15 @@ tree_to_gimple_tuple (tree *tp)
 
 /* 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_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)
@@ -3715,6 +3894,17 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
              || TREE_CODE (*expr_p) == GIMPLE_MODIFY_STMT
              || TREE_CODE (*expr_p) == INIT_EXPR);
 
+  /* Insert pointer conversions required by the middle-end that are not
+     required by the frontend.  This fixes middle-end type checking for
+     for example gcc.dg/redecl-6.c.  */
+  if (POINTER_TYPE_P (TREE_TYPE (*to_p))
+      && lang_hooks.types_compatible_p (TREE_TYPE (*to_p), TREE_TYPE (*from_p)))
+    {
+      STRIP_USELESS_TYPE_CONVERSION (*from_p);
+      if (!useless_type_conversion_p (TREE_TYPE (*to_p), TREE_TYPE (*from_p)))
+       *from_p = fold_convert (TREE_TYPE (*to_p), *from_p);
+    }
+
   /* 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);
@@ -4087,8 +4277,7 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
          if (TREE_CODE (op0) == INDIRECT_REF)
            goto do_indirect_ref;
 
-         /* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
-            is set properly.  */
+         /* Make sure TREE_CONSTANT and TREE_SIDE_EFFECTS are set properly.  */
          recompute_tree_invariant_for_addr_expr (expr);
 
          mark_addressable (TREE_OPERAND (expr, 0));
@@ -4532,7 +4721,7 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl)
          else
            return;
        }
-      else if (ctx->is_parallel)
+      else if (ctx->region_type != ORT_WORKSHARE)
        omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
 
       ctx = ctx->outer_context;
@@ -4725,8 +4914,9 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
   if (n == NULL)
     {
       enum omp_clause_default_kind default_kind, kind;
+      struct gimplify_omp_ctx *octx;
 
-      if (!ctx->is_parallel)
+      if (ctx->region_type == ORT_WORKSHARE)
        goto do_outer;
 
       /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be
@@ -4750,10 +4940,47 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
        case OMP_CLAUSE_DEFAULT_PRIVATE:
          flags |= GOVD_PRIVATE;
          break;
+       case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
+         flags |= GOVD_FIRSTPRIVATE;
+         break;
+       case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+         /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED.  */
+         gcc_assert (ctx->region_type == ORT_TASK);
+         if (ctx->outer_context)
+           omp_notice_variable (ctx->outer_context, decl, in_code);
+         for (octx = ctx->outer_context; octx; octx = octx->outer_context)
+           {
+             splay_tree_node n2;
+
+             n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl);
+             if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED)
+               {
+                 flags |= GOVD_FIRSTPRIVATE;
+                 break;
+               }
+             if ((octx->region_type & ORT_PARALLEL) != 0)
+               break;
+           }
+         if (flags & GOVD_FIRSTPRIVATE)
+           break;
+         if (octx == NULL
+             && (TREE_CODE (decl) == PARM_DECL
+                 || (!is_global_var (decl)
+                     && DECL_CONTEXT (decl) == current_function_decl)))
+           {
+             flags |= GOVD_FIRSTPRIVATE;
+             break;
+           }
+         flags |= GOVD_SHARED;
+         break;
        default:
          gcc_unreachable ();
        }
 
+      if ((flags & GOVD_PRIVATE)
+         && lang_hooks.decls.omp_private_outer_ref (decl))
+       flags |= GOVD_PRIVATE_OUTER_REF;
+
       omp_add_variable (ctx, decl, flags);
 
       shared = (flags & GOVD_SHARED) != 0;
@@ -4773,7 +5000,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
  do_outer:
   /* If the variable is private in the current context, then we don't
      need to propagate anything to an outer context.  */
-  if (flags & GOVD_PRIVATE)
+  if ((flags & GOVD_PRIVATE) && !(flags & GOVD_PRIVATE_OUTER_REF))
     return ret;
   if (ctx->outer_context
       && omp_notice_variable (ctx->outer_context, decl, in_code))
@@ -4806,7 +5033,7 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl)
        }
       else if ((n->value & GOVD_EXPLICIT) != 0
               && (ctx == gimplify_omp_ctxp
-                  || (ctx->is_combined_parallel
+                  || (ctx->region_type == ORT_COMBINED_PARALLEL
                       && gimplify_omp_ctxp->outer_context == ctx)))
        {
          if ((n->value & GOVD_FIRSTPRIVATE) != 0)
@@ -4819,7 +5046,7 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl)
       return true;
     }
 
-  if (ctx->is_parallel)
+  if (ctx->region_type != ORT_WORKSHARE)
     return false;
   else if (ctx->outer_context)
     return omp_is_private (ctx->outer_context, decl);
@@ -4848,7 +5075,7 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
       if (n != NULL)
        return (n->value & GOVD_SHARED) == 0;
     }
-  while (!ctx->is_parallel);
+  while (ctx->region_type == ORT_WORKSHARE);
   return false;
 }
 
@@ -4856,13 +5083,13 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
    and previous omp contexts.  */
 
 static void
-gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
-                          bool in_combined_parallel)
+gimplify_scan_omp_clauses (tree *list_p, tree *pre_p,
+                          enum omp_region_type region_type)
 {
   struct gimplify_omp_ctx *ctx, *outer_ctx;
   tree c;
 
-  ctx = new_omp_context (in_parallel, in_combined_parallel);
+  ctx = new_omp_context (region_type);
   outer_ctx = ctx->outer_context;
 
   while ((c = *list_p) != NULL)
@@ -4878,7 +5105,13 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
        {
        case OMP_CLAUSE_PRIVATE:
          flags = GOVD_PRIVATE | GOVD_EXPLICIT;
-         notice_outer = false;
+         if (lang_hooks.decls.omp_private_outer_ref (OMP_CLAUSE_DECL (c)))
+           {
+             flags |= GOVD_PRIVATE_OUTER_REF;
+             OMP_CLAUSE_PRIVATE_OUTER_REF (c) = 1;
+           }
+         else
+           notice_outer = false;
          goto do_add;
        case OMP_CLAUSE_SHARED:
          flags = GOVD_SHARED | GOVD_EXPLICIT;
@@ -4918,6 +5151,23 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
              pop_gimplify_context (OMP_CLAUSE_REDUCTION_MERGE (c));
              gimplify_omp_ctxp = outer_ctx;
            }
+         else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+                  && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+           {
+             gimplify_omp_ctxp = ctx;
+             push_gimplify_context ();
+             if (TREE_CODE (OMP_CLAUSE_LASTPRIVATE_STMT (c)) != BIND_EXPR)
+               {
+                 tree bind = build3 (BIND_EXPR, void_type_node, NULL,
+                                     NULL, NULL);
+                 TREE_SIDE_EFFECTS (bind) = 1;
+                 BIND_EXPR_BODY (bind) = OMP_CLAUSE_LASTPRIVATE_STMT (c);
+                 OMP_CLAUSE_LASTPRIVATE_STMT (c) = bind;
+               }
+             gimplify_stmt (&OMP_CLAUSE_LASTPRIVATE_STMT (c));
+             pop_gimplify_context (OMP_CLAUSE_LASTPRIVATE_STMT (c));
+             gimplify_omp_ctxp = outer_ctx;
+           }
          if (notice_outer)
            goto do_notice;
          break;
@@ -4934,7 +5184,7 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
          if (outer_ctx)
            omp_notice_variable (outer_ctx, decl, true);
          if (check_non_private
-             && !in_parallel
+             && region_type == ORT_WORKSHARE
              && omp_check_private (ctx, decl))
            {
              error ("%s variable %qs is private in outer context",
@@ -4958,6 +5208,8 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel,
 
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_UNTIED:
+       case OMP_CLAUSE_COLLAPSE:
          break;
 
        case OMP_CLAUSE_DEFAULT:
@@ -5036,7 +5288,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
   OMP_CLAUSE_CHAIN (clause) = *list_p;
   if (private_debug)
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
+  else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
+    OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
   *list_p = clause;
+  lang_hooks.decls.omp_finish_clause (clause);
 
   return 0;
 }
@@ -5093,6 +5348,8 @@ gimplify_adjust_omp_clauses (tree *list_p)
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_UNTIED:
+       case OMP_CLAUSE_COLLAPSE:
          break;
 
        default:
@@ -5122,8 +5379,10 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
 {
   tree expr = *expr_p;
 
-  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p, true,
-                            OMP_PARALLEL_COMBINED (expr));
+  gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p,
+                            OMP_PARALLEL_COMBINED (expr)
+                            ? ORT_COMBINED_PARALLEL
+                            : ORT_PARALLEL);
 
   push_gimplify_context ();
 
@@ -5139,120 +5398,187 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Gimplify the contents of an OMP_TASK statement.  This involves
+   gimplification of the body, as well as scanning the body for used
+   variables.  We need to do this scan now, because variable-sized
+   decls will be decomposed during gimplification.  */
+
+static enum gimplify_status
+gimplify_omp_task (tree *expr_p, tree *pre_p)
+{
+  tree expr = *expr_p;
+
+  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
+
+  push_gimplify_context ();
+
+  gimplify_stmt (&OMP_TASK_BODY (expr));
+
+  if (TREE_CODE (OMP_TASK_BODY (expr)) == BIND_EXPR)
+    pop_gimplify_context (OMP_TASK_BODY (expr));
+  else
+    pop_gimplify_context (NULL_TREE);
+
+  gimplify_adjust_omp_clauses (&OMP_TASK_CLAUSES (expr));
+
+  return GS_ALL_DONE;
+}
+
 /* Gimplify the gross structure of an OMP_FOR statement.  */
 
 static enum gimplify_status
 gimplify_omp_for (tree *expr_p, tree *pre_p)
 {
-  tree for_stmt, decl, var, t;
+  tree for_stmt, decl, var, t, bodylist;
   enum gimplify_status ret = GS_OK;
   tree body, init_decl = NULL_TREE;
+  int i;
 
   for_stmt = *expr_p;
 
-  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
+  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
+                            ORT_WORKSHARE);
 
-  t = OMP_FOR_INIT (for_stmt);
-  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)));
+  /* If OMP_FOR is re-gimplified, ensure all variables in pre-body
+     are noticed.  */
+  gimplify_stmt (&OMP_FOR_PRE_BODY (for_stmt));
 
-  /* Make sure the iteration variable is private.  */
-  if (omp_is_private (gimplify_omp_ctxp, decl))
-    omp_notice_variable (gimplify_omp_ctxp, decl, true);
-  else
-    omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
+  bodylist = alloc_stmt_list ();
 
-  /* 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))
+  gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
+             == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt)));
+  gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
+             == TREE_VEC_LENGTH (OMP_FOR_INCR (for_stmt)));
+  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
     {
-      var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
-      GENERIC_TREE_OPERAND (t, 0) = var;
+      t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+      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))
+                 || POINTER_TYPE_P (TREE_TYPE (decl)));
 
-      init_decl = build_gimple_modify_stmt (decl, var);
-      omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
-    }
-  else
-    var = decl;
+      /* Make sure the iteration variable is private.  */
+      if (omp_is_private (gimplify_omp_ctxp, decl))
+       omp_notice_variable (gimplify_omp_ctxp, decl, true);
+      else
+       omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
 
-  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
-                       &OMP_FOR_PRE_BODY (for_stmt),
-                       NULL, is_gimple_val, fb_rvalue);
+      /* 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;
 
-  tree_to_gimple_tuple (&OMP_FOR_INIT (for_stmt));
+         init_decl = build_gimple_modify_stmt (decl, var);
+         omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+       }
+      else
+       var = decl;
 
-  t = OMP_FOR_COND (for_stmt);
-  gcc_assert (COMPARISON_CLASS_P (t));
-  gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
-  TREE_OPERAND (t, 0) = var;
+      ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                           &OMP_FOR_PRE_BODY (for_stmt),
+                           NULL, is_gimple_val, fb_rvalue);
 
-  ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
-                       &OMP_FOR_PRE_BODY (for_stmt),
-                       NULL, is_gimple_val, fb_rvalue);
+      tree_to_gimple_tuple (&TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i));
 
-  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 = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
-      t = build_gimple_modify_stmt (var, t);
-      OMP_FOR_INCR (for_stmt) = t;
-      break;
+      t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+      gcc_assert (COMPARISON_CLASS_P (t));
+      gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
+      TREE_OPERAND (t, 0) = var;
 
-    case PREDECREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      t = build_int_cst (TREE_TYPE (decl), -1);
-      t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
-      t = build_gimple_modify_stmt (var, t);
-      OMP_FOR_INCR (for_stmt) = t;
-      break;
-      
-    case GIMPLE_MODIFY_STMT:
-      gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
-      GIMPLE_STMT_OPERAND (t, 0) = var;
+      ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
+                           &OMP_FOR_PRE_BODY (for_stmt),
+                           NULL, is_gimple_val, fb_rvalue);
 
-      t = GIMPLE_STMT_OPERAND (t, 1);
+      tree_to_gimple_tuple (&TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i));
+      t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
       switch (TREE_CODE (t))
        {
-       case PLUS_EXPR:
-         if (TREE_OPERAND (t, 1) == decl)
+       case PREINCREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+         t = build_int_cst (TREE_TYPE (decl), 1);
+         t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+         t = build_gimple_modify_stmt (var, t);
+         TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
+         break;
+
+       case PREDECREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+         t = build_int_cst (TREE_TYPE (decl), -1);
+         t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
+         t = build_gimple_modify_stmt (var, t);
+         TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
+         break;
+
+       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))
            {
-             TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
+           case PLUS_EXPR:
+             if (TREE_OPERAND (t, 1) == decl)
+               {
+                 TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
+                 TREE_OPERAND (t, 0) = var;
+                 break;
+               }
+
+             /* Fallthru.  */
+           case MINUS_EXPR:
+           case POINTER_PLUS_EXPR:
+             gcc_assert (TREE_OPERAND (t, 0) == decl);
              TREE_OPERAND (t, 0) = var;
              break;
+           default:
+             gcc_unreachable ();
            }
 
-         /* Fallthru.  */
-       case MINUS_EXPR:
-         gcc_assert (TREE_OPERAND (t, 0) == decl);
-         TREE_OPERAND (t, 0) = var;
+         ret |= gimplify_expr (&TREE_OPERAND (t, 1),
+                               &OMP_FOR_PRE_BODY (for_stmt),
+                               NULL, is_gimple_val, fb_rvalue);
          break;
+
        default:
          gcc_unreachable ();
        }
 
-      ret |= gimplify_expr (&TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt),
-                           NULL, is_gimple_val, fb_rvalue);
-      break;
+      if (init_decl)
+       append_to_statement_list (init_decl, &bodylist);
 
-    default:
-      gcc_unreachable ();
+      if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+       {
+         tree c;
+         for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c))
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+             && OMP_CLAUSE_DECL (c) == decl
+             && OMP_CLAUSE_LASTPRIVATE_STMT (c) == NULL)
+           {
+             t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+             gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+             gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
+             t = GIMPLE_STMT_OPERAND (t, 1);
+             gcc_assert (TREE_CODE (t) == PLUS_EXPR
+                         || TREE_CODE (t) == MINUS_EXPR
+                         || TREE_CODE (t) == POINTER_PLUS_EXPR);
+             gcc_assert (TREE_OPERAND (t, 0) == var);
+             t = build2 (TREE_CODE (t), TREE_TYPE (decl), decl,
+                         TREE_OPERAND (t, 1));
+             OMP_CLAUSE_LASTPRIVATE_STMT (c)
+               = build_gimple_modify_stmt (decl, t);
+           }
+       }
     }
 
   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;
+  append_to_statement_list (body, &bodylist);
+  OMP_FOR_BODY (for_stmt) = bodylist;
   gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
 
   return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
@@ -5266,7 +5592,7 @@ gimplify_omp_workshare (tree *expr_p, tree *pre_p)
 {
   tree stmt = *expr_p;
 
-  gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, false, false);
+  gimplify_scan_omp_clauses (&OMP_CLAUSES (stmt), pre_p, ORT_WORKSHARE);
   gimplify_to_stmt_list (&OMP_BODY (stmt));
   gimplify_adjust_omp_clauses (&OMP_CLAUSES (stmt));
 
@@ -5283,16 +5609,32 @@ goa_lhs_expr_p (tree expr, tree addr)
   /* Also include casts to other type variants.  The C front end is fond
      of adding these for e.g. volatile variables.  This is like 
      STRIP_TYPE_NOPS but includes the main variant lookup.  */
-  while ((TREE_CODE (expr) == NOP_EXPR
-          || TREE_CODE (expr) == CONVERT_EXPR
+  while ((CONVERT_EXPR_P (expr)
           || TREE_CODE (expr) == NON_LVALUE_EXPR)
          && TREE_OPERAND (expr, 0) != error_mark_node
          && (TYPE_MAIN_VARIANT (TREE_TYPE (expr))
              == 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
+            && (CONVERT_EXPR_P (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);
+       }
+      if (expr == addr)
+       return true;
+      return (TREE_CODE (addr) == ADDR_EXPR
+             && TREE_CODE (expr) == ADDR_EXPR
+             && TREE_OPERAND (addr, 0) == TREE_OPERAND (expr, 0));
+    }
   if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0))
     return true;
   return false;
@@ -5548,8 +5890,14 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case TRUTH_NOT_EXPR:
-         TREE_OPERAND (*expr_p, 0)
-           = gimple_boolify (TREE_OPERAND (*expr_p, 0));
+         if (TREE_CODE (TREE_TYPE (*expr_p)) != BOOLEAN_TYPE)
+           {
+             tree type = TREE_TYPE (*expr_p);
+             *expr_p = fold_convert (type, gimple_boolify (*expr_p));
+             ret = GS_OK;
+             break;
+           }
+
          ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                               is_gimple_val, fb_rvalue);
          recalculate_side_effects (*expr_p);
@@ -5563,8 +5911,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
          break;
 
-       case CONVERT_EXPR:
-       case NOP_EXPR:
+       CASE_CONVERT:
          if (IS_EMPTY_STMT (*expr_p))
            {
              ret = GS_ALL_DONE;
@@ -5660,6 +6007,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
                                 NULL, is_gimple_val, fb_rvalue);
          break;
 
+         /* Predictions are always gimplified.  */
+       case PREDICT_EXPR:
+         goto out;
+
        case LABEL_EXPR:
          ret = GS_ALL_DONE;
          gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
@@ -5823,6 +6174,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_omp_parallel (expr_p, pre_p);
          break;
 
+       case OMP_TASK:
+         ret = gimplify_omp_task (expr_p, pre_p);
+         break;
+
        case OMP_FOR:
          ret = gimplify_omp_for (expr_p, pre_p);
          break;
@@ -5845,12 +6200,19 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
        case OMP_RETURN:
        case OMP_CONTINUE:
-        case OMP_ATOMIC_LOAD:
-        case OMP_ATOMIC_STORE:
-
+       case OMP_ATOMIC_STORE:
+       case OMP_SECTIONS_SWITCH:
          ret = GS_ALL_DONE;
          break;
 
+       case OMP_ATOMIC_LOAD:
+         if (gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, NULL,
+             is_gimple_val, fb_rvalue) != GS_ALL_DONE)
+           ret = GS_ERROR;
+         else
+           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.
@@ -6286,7 +6648,7 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
   unshare_body (body_p, fndecl);
   unvisit_body (body_p, fndecl);
 
-  /* Make sure input_location isn't set to something wierd.  */
+  /* Make sure input_location isn't set to something weird.  */
   input_location = DECL_SOURCE_LOCATION (fndecl);
 
   /* Resolve callee-copies.  This has to be done before processing
@@ -6370,7 +6732,7 @@ gimplify_function_tree (tree fndecl)
 
   ret = DECL_RESULT (fndecl);
   if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
-          || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
+       || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
       && !needs_to_live_in_memory (ret))
     DECL_GIMPLE_REG_P (ret) = 1;
 
@@ -6404,7 +6766,6 @@ gimplify_function_tree (tree fndecl)
       DECL_SAVED_TREE (fndecl) = bind;
     }
 
-  cfun->gimplified = true;
   current_function_decl = oldfn;
   pop_cfun ();
 }
@@ -6430,6 +6791,7 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
 
   push_gimplify_context ();
   gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
+  gimplify_ctxp->allow_rhs_cond_expr = true;
 
   if (var)
     expr = build_gimple_modify_stmt (var, expr);