OSDN Git Service

2008-06-08 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 462e4a2..47a2fe7 100644 (file)
@@ -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
@@ -270,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;
 
@@ -279,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;
 }
@@ -756,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);
@@ -4711,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;
@@ -4904,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
@@ -4929,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;
@@ -4952,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))
@@ -4985,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)
@@ -4998,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);
@@ -5027,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;
 }
 
@@ -5035,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)
@@ -5057,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;
@@ -5097,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;
@@ -5113,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",
@@ -5137,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:
@@ -5215,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;
 }
@@ -5272,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:
@@ -5301,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 ();
 
@@ -5318,124 +5398,187 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
   return GS_ALL_DONE;
 }
 
-/* Gimplify the gross structure of an OMP_FOR statement.  */
+/* 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_for (tree *expr_p, tree *pre_p)
+gimplify_omp_task (tree *expr_p, tree *pre_p)
 {
-  tree for_stmt, decl, var, t;
-  enum gimplify_status ret = GS_OK;
-  tree body, init_decl = NULL_TREE;
+  tree expr = *expr_p;
 
-  for_stmt = *expr_p;
+  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
 
-  gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, false, false);
+  push_gimplify_context ();
 
-  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)));
+  gimplify_stmt (&OMP_TASK_BODY (expr));
 
-  /* Make sure the iteration variable is private.  */
-  if (omp_is_private (gimplify_omp_ctxp, decl))
-    omp_notice_variable (gimplify_omp_ctxp, decl, true);
+  if (TREE_CODE (OMP_TASK_BODY (expr)) == BIND_EXPR)
+    pop_gimplify_context (OMP_TASK_BODY (expr));
   else
-    omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
+    pop_gimplify_context (NULL_TREE);
 
-  /* 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;
+  gimplify_adjust_omp_clauses (&OMP_TASK_CLAUSES (expr));
 
-      init_decl = build_gimple_modify_stmt (decl, var);
-      omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
-    }
-  else
-    var = decl;
+  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, 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,
+                            ORT_WORKSHARE);
 
   /* 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);
+  bodylist = alloc_stmt_list ();
+
+  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++)
+    {
+      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)));
+
+      /* 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);
 
-  tree_to_gimple_tuple (&OMP_FOR_INIT (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;
 
-  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;
+         init_decl = build_gimple_modify_stmt (decl, var);
+         omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+       }
+      else
+       var = decl;
 
-  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 (&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;
+      tree_to_gimple_tuple (&TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i));
 
-    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;
+      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;
 
-      t = GIMPLE_STMT_OPERAND (t, 1);
+      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_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;
@@ -5449,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));
 
@@ -5747,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);
@@ -6025,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;
@@ -6048,6 +6201,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
        case OMP_RETURN:
        case OMP_CONTINUE:
        case OMP_ATOMIC_STORE:
+       case OMP_SECTIONS_SWITCH:
          ret = GS_ALL_DONE;
          break;