OSDN Git Service

2008-02-10 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / omp-low.c
index 20f36e0..ca00266 100644 (file)
@@ -3,7 +3,7 @@
    marshalling to implement data sharing and copying clauses.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
-   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -529,6 +529,7 @@ copy_var_decl (tree var, tree name, tree type)
   DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
   DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
   DECL_CONTEXT (copy) = DECL_CONTEXT (var);
+  DECL_SOURCE_LOCATION (copy) = DECL_SOURCE_LOCATION (var);
   TREE_USED (copy) = 1;
   DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
 
@@ -1518,12 +1519,10 @@ lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
   tree t;
   omp_context *up;
 
-  gcc_assert (ctx->is_nested);
-
   for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
     t = maybe_lookup_decl (decl, up);
 
-  gcc_assert (t || is_global_var (decl));
+  gcc_assert (!ctx->is_nested || t || is_global_var (decl));
 
   return t ? t : decl;
 }
@@ -1538,9 +1537,8 @@ maybe_lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
   tree t = NULL;
   omp_context *up;
 
-  if (ctx->is_nested)
-    for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
-      t = maybe_lookup_decl (decl, up);
+  for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
+    t = maybe_lookup_decl (decl, up);
 
   return t ? t : decl;
 }
@@ -2012,7 +2010,7 @@ lower_copyprivate_clauses (tree clauses, tree *slist, tree *rlist,
       by_ref = use_pointer_for_field (var, false);
 
       ref = build_sender_ref (var, ctx);
-      x = (ctx->is_nested) ? lookup_decl_in_outer_ctx (var, ctx) : var;
+      x = lookup_decl_in_outer_ctx (var, ctx);
       x = by_ref ? build_fold_addr_expr (x) : x;
       x = build_gimple_modify_stmt (ref, x);
       gimplify_and_add (x, slist);
@@ -2053,9 +2051,8 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
          continue;
        }
 
-      var = val = OMP_CLAUSE_DECL (c);
-      if (ctx->is_nested)
-       var = lookup_decl_in_outer_ctx (val, ctx);
+      val = OMP_CLAUSE_DECL (c);
+      var = lookup_decl_in_outer_ctx (val, ctx);
 
       if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN
          && is_global_var (var))
@@ -2127,13 +2124,10 @@ lower_send_shared_vars (tree *ilist, tree *olist, omp_context *ctx)
       if (!nvar || !DECL_HAS_VALUE_EXPR_P (nvar))
        continue;
 
-      var = ovar;
-
       /* If CTX is a nested parallel directive.  Find the immediately
         enclosing parallel or workshare construct that contains a
         mapping for OVAR.  */
-      if (ctx->is_nested)
-       var = lookup_decl_in_outer_ctx (ovar, ctx);
+      var = lookup_decl_in_outer_ctx (ovar, ctx);
 
       if (use_pointer_for_field (ovar, true))
        {
@@ -2433,6 +2427,61 @@ remove_exit_barriers (struct omp_region *region)
     }
 }
 
+/* Optimize omp_get_thread_num () and omp_get_num_threads ()
+   calls.  These can't be declared as const functions, but
+   within one parallel body they are constant, so they can be
+   transformed there into __builtin_omp_get_{thread_num,num_threads} ()
+   which are declared const.  */
+
+static void
+optimize_omp_library_calls (void)
+{
+  basic_block bb;
+  block_stmt_iterator bsi;
+  tree thr_num_id
+    = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM]);
+  tree num_thr_id
+    = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS]);
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       tree stmt = bsi_stmt (bsi);
+       tree call = get_call_expr_in (stmt);
+       tree decl;
+
+       if (call
+           && (decl = get_callee_fndecl (call))
+           && DECL_EXTERNAL (decl)
+           && TREE_PUBLIC (decl)
+           && DECL_INITIAL (decl) == NULL)
+         {
+           tree built_in;
+
+           if (DECL_NAME (decl) == thr_num_id)
+             built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+           else if (DECL_NAME (decl) == num_thr_id)
+             built_in = built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS];
+           else
+             continue;
+
+           if (DECL_ASSEMBLER_NAME (decl) != DECL_ASSEMBLER_NAME (built_in)
+               || call_expr_nargs (call) != 0)
+             continue;
+
+           if (flag_exceptions && !TREE_NOTHROW (decl))
+             continue;
+
+           if (TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE
+               || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl)))
+                  != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (built_in))))
+             continue;
+
+           CALL_EXPR_FN (call) = build_fold_addr_expr (built_in);
+         }
+      }
+}
+
 /* Expand the OpenMP parallel directive starting at REGION.  */
 
 static void
@@ -2448,6 +2497,9 @@ expand_omp_parallel (struct omp_region *region)
   entry_stmt = last_stmt (region->entry);
   child_fn = OMP_PARALLEL_FN (entry_stmt);
   child_cfun = DECL_STRUCT_FUNCTION (child_fn);
+  /* If this function has been already instrumented, make sure
+     the child function isn't instrumented again.  */
+  child_cfun->after_tree_profile = cfun->after_tree_profile;
 
   entry_bb = region->entry;
   exit_bb = region->exit;
@@ -2595,7 +2647,27 @@ expand_omp_parallel (struct omp_region *region)
       /* Fix the callgraph edges for child_cfun.  Those for cfun will be
         fixed in a following pass.  */
       push_cfun (child_cfun);
+      if (optimize)
+       optimize_omp_library_calls ();
       rebuild_cgraph_edges ();
+
+      /* Some EH regions might become dead, see PR34608.  If
+        pass_cleanup_cfg isn't the first pass to happen with the
+        new child, these dead EH edges might cause problems.
+        Clean them up now.  */
+      if (flag_exceptions)
+       {
+         basic_block bb;
+         tree save_current = current_function_decl;
+         bool changed = false;
+
+         current_function_decl = child_fn;
+         FOR_EACH_BB (bb)
+           changed |= tree_purge_dead_eh_edges (bb);
+         if (changed)
+           cleanup_tree_cfg ();
+         current_function_decl = save_current;
+       }
       pop_cfun ();
     }
   
@@ -3268,6 +3340,16 @@ expand_omp_for (struct omp_region *region)
   extract_omp_for_data (last_stmt (region->entry), &fd);
   region->sched_kind = fd.sched_kind;
 
+  gcc_assert (EDGE_COUNT (region->entry->succs) == 2);
+  BRANCH_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
+  FALLTHRU_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
+  if (region->cont)
+    {
+      gcc_assert (EDGE_COUNT (region->cont->succs) == 2);
+      BRANCH_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
+      FALLTHRU_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
+    }
+
   if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
       && !fd.have_ordered
       && region->cont != NULL)
@@ -3902,6 +3984,11 @@ expand_omp (struct omp_region *region)
 {
   while (region)
     {
+      /* First, determine whether this is a combined parallel+workshare
+                region.  */
+      if (region->type == OMP_PARALLEL)
+       determine_parallel_type (region);
+
       if (region->inner)
        expand_omp (region->inner);
 
@@ -3978,11 +4065,6 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
          region = parent;
          region->exit = bb;
          parent = parent->outer;
-
-         /* If REGION is a parallel region, determine whether it is
-            a combined parallel+workshare region.  */
-         if (region->type == OMP_PARALLEL)
-           determine_parallel_type (region);
        }
       else if (code == OMP_ATOMIC_STORE)
        {