This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp] fix type mapping and nested function problems


Fixes a horde of Fortran problems.  We interacted badly with some of
the transformations done by nested functions.  We need to remap all
varying types, which includes pointers to variable sized types.  And
there were a smattering of other type-correctness problems that are
solved by making sure the remapping is done centrally before we start
generating any code, including DECL_VALUE_EXPRs.


r~


        * omp-low.c (build_receiver_ref): Lookup receiver field again.
        (build_outer_var_ref): Don't remap types here.
        (install_var_field): Assert no duplicate fields.
        (install_var_local): Rename from install_var_new; do
        omp_copy_decl_1 here.
        (install_var_private, install_var_shared): Remove.
        (fixup_remapped_decl): Rename from fixup_variable_sized.  Remap
        types of all decls seen.
        (is_private_var): Remove.
        (fixup_child_record_type): New.
        (scan_sharing_clauses): Always run second pass for
        fixup_remapped_decl; use install_var_local.
        (create_omp_child_function): Make the passed-as argument type
        be void*.
        (scan_omp_parallel): Call fixup_child_record_type.
        (scan_omp_for): Don't privatize iterator variable here.
        (expand_rec_input_clauses): Handle variable sized reference vars.
        Set DECL_VALUE_EXPR for shared variables.
        (expand_omp_parallel): Expand body after expand_rec_input_clauses.
        (expand_omp_single): Likewise.
        * tree-nested.c (struct nesting_info): Add field_map,
        suppress_expansion, debug_var_chain.
        (create_nesting_tree): Initialize them.
        (lookup_field_for_decl): Use field_map.
        (get_nonlocal_debug_decl, get_local_debug_decl): New.
        (convert_nonlocal_reference, convert_local_reference): Use them.
        Honor suppress_expansion; set it for OMP statements.
        (convert_nonlocal_omp_clauses): Fill in suppress_expansion.
        (convert_local_omp_clauses): Similarly.
        (finalize_nesting_tree_1): Add debug_var_chain to toplevel block.

Index: gcc/omp-low.c
===================================================================
--- gcc/omp-low.c	(revision 106281)
+++ gcc/omp-low.c	(working copy)
@@ -242,6 +242,12 @@ build_receiver_ref (tree var, bool by_re
 {
   tree x, field = lookup_field (var, ctx);
 
+  /* If the receiver record type was remapped in the child function,
+     remap the field into the new record type.  */
+  x = maybe_lookup_field (field, ctx);
+  if (x != NULL)
+    field = x;
+
   x = build_fold_indirect_ref (ctx->receiver_decl);
   x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL);
   if (by_ref)
@@ -263,8 +269,6 @@ build_outer_var_ref (tree var, omp_conte
     {
       x = TREE_OPERAND (DECL_VALUE_EXPR (var), 0);
       x = build_outer_var_ref (x, ctx);
-      if (is_parallel_ctx (ctx))
-	x = fold_convert (remap_type (TREE_TYPE (x), &ctx->cb), x);
       x = build_fold_indirect_ref (x);
     }
   else if (is_parallel_ctx (ctx))
@@ -300,10 +304,7 @@ install_var_field (tree var, bool by_ref
 {
   tree field, type;
 
-  /* We can have both firstprivate and lastprivate on a parallel.
-     Avoid creating two fields.  */
-  if (maybe_lookup_field (var, ctx) != NULL)
-    return;
+  gcc_assert (!splay_tree_lookup (ctx->field_map, (splay_tree_key) var));
 
   type = TREE_TYPE (var);
   if (by_ref)
@@ -323,95 +324,45 @@ install_var_field (tree var, bool by_ref
 }
 
 static tree
-install_var_new (tree new_var, tree var, omp_context *ctx)
+install_var_local (tree var, omp_context *ctx)
 {
+  tree new_var = omp_copy_decl_1 (var, ctx);
   insert_decl_map (&ctx->cb, var, new_var);
   return new_var;
 }
 
-/* Install in CTX a new variable to stand as a local private for VAR.  */
-
-static tree
-install_var_private (tree var, omp_context *ctx)
-{
-  tree new_var;
-  new_var = omp_copy_decl_1 (var, ctx);
-  if (is_reference (var))
-    {
-      tree tmp_name = DECL_NAME (var), x;
-
-      if (tmp_name != NULL)
-	tmp_name = create_tmp_var_name (IDENTIFIER_POINTER (tmp_name));
-      x = omp_copy_decl_2 (var, tmp_name, TREE_TYPE (TREE_TYPE (var)), ctx);
-      DECL_ARTIFICIAL (x) = 1;
-      DECL_IGNORED_P (x) = 1;
-      DECL_ABSTRACT_ORIGIN (x) = NULL;
-      x = fold_convert (TREE_TYPE (var), build_fold_addr_expr (x));
-      DECL_INITIAL (new_var) = x;
-    }
-  return install_var_new (new_var, var, ctx);
-}
-
-/* Install in CTX a substitution to implement shared semantics for VAR.  */
-
-static tree
-install_var_shared (tree var, bool by_ref, omp_context *ctx)
-{
-  tree x = build_receiver_ref (var, by_ref, ctx);
-  tree new_var = omp_copy_decl_1 (var, ctx);
-  SET_DECL_VALUE_EXPR (new_var, x);
-  DECL_HAS_VALUE_EXPR_P (new_var) = 1;
-  return install_var_new (new_var, var, ctx);
-}
-
 /* Adjust the replacement for DECL in CTX for the new context.  This means
    copying the DECL_VALUE_EXPR, and fixing up the type.  */
 
 static void
-fixup_variable_sized (tree decl, omp_context *ctx)
+fixup_remapped_decl (tree decl, omp_context *ctx)
 {
-  tree new_decl, ve;
+  tree new_decl, size;
 
   new_decl = lookup_decl (decl, ctx);
-  ve = DECL_VALUE_EXPR (decl);
 
-  walk_tree (&ve, copy_body_r, &ctx->cb, NULL);
-  SET_DECL_VALUE_EXPR (new_decl, ve);
-  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
-
-  DECL_SIZE (new_decl) = remap_decl (DECL_SIZE (decl), &ctx->cb);
-  DECL_SIZE_UNIT (new_decl)
-    = remap_decl (DECL_SIZE_UNIT (decl), &ctx->cb);
   TREE_TYPE (new_decl) = remap_type (TREE_TYPE (decl), &ctx->cb);
-}
 
-/* Return true if VAR is private in the context of the enclosing parallel.  */
-
-static bool
-is_private_var (tree var, omp_context *ctx)
-{
-  tree new_var;
-
-  while (1)
+  if (!TREE_CONSTANT (DECL_SIZE (new_decl)))
     {
-      new_var = maybe_lookup_decl (var, ctx);
-      if (new_var)
-	return !DECL_HAS_VALUE_EXPR_P (new_var);
-      if (is_parallel_ctx (ctx))
-	break;
-      ctx = ctx->outer;
+      if (DECL_HAS_VALUE_EXPR_P (decl))
+	{
+	  tree ve = DECL_VALUE_EXPR (decl);
+	  walk_tree (&ve, copy_body_r, &ctx->cb, NULL);
+	  SET_DECL_VALUE_EXPR (new_decl, ve);
+	  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+	}
 
-      /* If we reached the top of the contexts without hitting a parallel,
-	 then the original context is not lexically nested within a parallel
- 	 and any local variable is automatically private.  */
-      if (ctx == NULL)
-	return !is_global_var (var);
+      size = remap_decl (DECL_SIZE (decl), &ctx->cb);
+      if (size == error_mark_node)
+	size = TYPE_SIZE (TREE_TYPE (new_decl));
+      DECL_SIZE (new_decl) = size;
+
+      size = remap_decl (DECL_SIZE_UNIT (decl), &ctx->cb);
+      if (size == error_mark_node)
+	size = TYPE_SIZE_UNIT (TREE_TYPE (new_decl));
+      DECL_SIZE_UNIT (new_decl) = size;
     }
-
-  if (DECL_ARTIFICIAL (var))
-    return false;
-  else
-    return ctx->default_kind == OMP_CLAUSE_DEFAULT_PRIVATE;
 }
 
 /* The callback for remap_decl.  Search all containing contexts for a
@@ -510,13 +461,56 @@ delete_omp_context (splay_tree_value val
   XDELETE (ctx);
 }
 
+/* Fix up RECEIVER_DECL with a type that has been remapped to the child
+   context.  */
+
+static void
+fixup_child_record_type (omp_context *ctx)
+{
+  tree f, type = ctx->record_type;
+
+  /* ??? It isn't sufficient to just call remap_type here, because
+     variably_modified_type_p doesn't work the way we expect for
+     record types.  Testing each field for whether it needs remapping
+     and creating a new record by hand works, however.  */
+  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+    if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
+      break;
+  if (f)
+    {
+      tree name, new_fields = NULL;
+
+      type = lang_hooks.types.make_type (RECORD_TYPE);
+      name = DECL_NAME (TYPE_NAME (ctx->record_type));
+      name = build_decl (TYPE_DECL, name, type);
+      TYPE_NAME (type) = name;
+
+      for (f = TYPE_FIELDS (ctx->record_type); f ; f = TREE_CHAIN (f))
+	{
+	  tree new_f = copy_node (f);
+	  DECL_CONTEXT (new_f) = type;
+	  TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &ctx->cb);
+	  TREE_CHAIN (new_f) = new_fields;
+	  new_fields = new_f;
+
+	  /* Arrange to be able to look up the receiver field
+	     given the sender field.  */
+	  splay_tree_insert (ctx->field_map, (splay_tree_key) f,
+			     (splay_tree_value) new_f);
+	}
+      TYPE_FIELDS (type) = nreverse (new_fields);
+      layout_type (type);
+    }
+
+  TREE_TYPE (ctx->receiver_decl) = build_pointer_type (type);
+}
+
 /* Instantiate decls as necessary in CTX to satisfy the data sharing
    specified by CLAUSES.  */
 
 static void
 scan_sharing_clauses (tree clauses, omp_context *ctx)
 {
-  bool saw_var_sized = false;
   tree c, decl;
 
   for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
@@ -527,23 +521,22 @@ scan_sharing_clauses (tree clauses, omp_
 	{
 	case OMP_CLAUSE_PRIVATE:
 	  decl = OMP_CLAUSE_DECL (c);
-	  if (is_variable_sized (decl))
-	    saw_var_sized = true;
-	  install_var_private (decl, ctx);
+	  if (!is_variable_sized (decl))
+	    install_var_local (decl, ctx);
 	  break;
 
 	case OMP_CLAUSE_SHARED:
 	  gcc_assert (is_parallel_ctx (ctx));
 	  decl = OMP_CLAUSE_DECL (c);
-	  by_ref = use_pointer_for_field (decl, true);
 	  gcc_assert (!is_variable_sized (decl));
+	  by_ref = use_pointer_for_field (decl, true);
 	  if (! TREE_READONLY (decl)
 	      || TREE_ADDRESSABLE (decl)
 	      || by_ref
 	      || is_reference (decl))
 	    {
 	      install_var_field (decl, by_ref, ctx);
-	      install_var_shared (decl, by_ref, ctx);
+	      install_var_local (decl, ctx);
 	      break;
 	    }
 	  /* We don't need to copy const scalar vars back.  */
@@ -551,7 +544,8 @@ scan_sharing_clauses (tree clauses, omp_
 	  goto do_private;
 
 	case OMP_CLAUSE_LASTPRIVATE:
-	  /* Let the corresponding firstprivate clause create the variable.  */
+	  /* Let the corresponding firstprivate clause create
+	     the variable.  */
 	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
 	    break;
 	  /* FALLTHRU */
@@ -561,13 +555,13 @@ scan_sharing_clauses (tree clauses, omp_
 	  decl = OMP_CLAUSE_DECL (c);
 	do_private:
 	  if (is_variable_sized (decl))
-	    saw_var_sized = true;
+	    break;
 	  else if (is_parallel_ctx (ctx))
 	    {
 	      by_ref = use_pointer_for_field (decl, false);
 	      install_var_field (decl, by_ref, ctx);
 	    }
-	  install_var_private (decl, ctx);
+	  install_var_local (decl, ctx);
 	  break;
 
 	case OMP_CLAUSE_COPYPRIVATE:
@@ -601,30 +595,45 @@ scan_sharing_clauses (tree clauses, omp_
 	}
     }
 
-  /* Instantiate the VALUE_EXPR for variable sized variables.  We have
-     to do this as a separate pass, since we need the pointer and size
-     decls installed first.  */
-  if (saw_var_sized)
-    for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
-      {
-	switch (TREE_CODE (c))
-	  {
-	  case OMP_CLAUSE_PRIVATE:
-	  case OMP_CLAUSE_FIRSTPRIVATE:
-	  case OMP_CLAUSE_REDUCTION:
-	  case OMP_CLAUSE_SHARED:
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      switch (TREE_CODE (c))
+	{
+	case OMP_CLAUSE_LASTPRIVATE:
+	  /* Let the corresponding firstprivate clause create
+	     the variable.  */
+	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
 	    break;
-	  case OMP_CLAUSE_LASTPRIVATE:
-	    if (!OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
-	      break;
-	  default:
-	    continue;
-	  }
+	  /* FALLTHRU */
 
-	decl = OMP_CLAUSE_DECL (c);
-	if (is_variable_sized (decl))
-	  fixup_variable_sized (decl, ctx);
-      }
+	case OMP_CLAUSE_PRIVATE:
+	case OMP_CLAUSE_FIRSTPRIVATE:
+	case OMP_CLAUSE_REDUCTION:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (is_variable_sized (decl))
+	    install_var_local (decl, ctx);
+	  fixup_remapped_decl (decl, ctx);
+	  break;
+
+	case OMP_CLAUSE_SHARED:
+	  decl = OMP_CLAUSE_DECL (c);
+	  fixup_remapped_decl (decl, ctx);
+	  break;
+
+	case OMP_CLAUSE_COPYPRIVATE:
+	case OMP_CLAUSE_COPYIN:
+	case OMP_CLAUSE_DEFAULT:
+	case OMP_CLAUSE_IF:
+	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_SCHEDULE:
+	case OMP_CLAUSE_NOWAIT:
+	case OMP_CLAUSE_ORDERED:
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -656,12 +665,10 @@ create_omp_child_function_name (void)
 static void
 create_omp_child_function (omp_context *ctx)
 {
-  tree decl, ptype, type, name, t;
-
-  ptype = build_pointer_type (ctx->record_type);
+  tree decl, type, name, t;
 
   name = create_omp_child_function_name ();
-  type = build_function_type_list (void_type_node, ptype, NULL_TREE);
+  type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
 
   decl = build_decl (FUNCTION_DECL, name, type);
   decl = lang_hooks.decls.pushdecl (decl);
@@ -682,9 +689,9 @@ create_omp_child_function (omp_context *
   DECL_IGNORED_P (t) = 1;
   DECL_RESULT (decl) = t;
 
-  t = build_decl (PARM_DECL, get_identifier (".omp_data_i"), ptype);
+  t = build_decl (PARM_DECL, get_identifier (".omp_data_i"), ptr_type_node);
   DECL_ARTIFICIAL (t) = 1;
-  DECL_ARG_TYPE (t) = ptype;
+  DECL_ARG_TYPE (t) = ptr_type_node;
   DECL_CONTEXT (t) = decl;
   TREE_USED (t) = 1;
   DECL_ARGUMENTS (decl) = t;
@@ -694,8 +701,8 @@ create_omp_child_function (omp_context *
      allocate_struct_function clobbers cfun, so we need to restore
      it afterward.  */
   allocate_struct_function (decl);
-  DECL_SOURCE_LOCATION (decl) = input_location;
-  cfun->function_end_locus = input_location;
+  DECL_SOURCE_LOCATION (decl) = EXPR_LOCATION (ctx->stmt);
+  cfun->function_end_locus = EXPR_LOCATION (ctx->stmt);
   cfun = ctx->cb.src_cfun;
 }
 
@@ -715,7 +722,6 @@ scan_omp_parallel (tree *stmt_p, omp_con
   name = create_tmp_var_name (".omp_data_s");
   name = build_decl (TYPE_DECL, name, ctx->record_type);
   TYPE_NAME (ctx->record_type) = name;
-
   create_omp_child_function (ctx);
 
   scan_sharing_clauses (OMP_PARALLEL_CLAUSES (*stmt_p), ctx);
@@ -724,7 +730,10 @@ scan_omp_parallel (tree *stmt_p, omp_con
   if (TYPE_FIELDS (ctx->record_type) == NULL)
     ctx->record_type = ctx->receiver_decl = NULL;
   else
-    layout_type (ctx->record_type);
+    {
+      layout_type (ctx->record_type);
+      fixup_child_record_type (ctx);
+    }
 }
 
 /* Scan an OpenMP loop directive.  */
@@ -733,21 +742,11 @@ static void
 scan_omp_for (tree *stmt_p, omp_context *outer_ctx)
 {
   omp_context *ctx;
-  tree iter, stmt = *stmt_p;
+  tree stmt = *stmt_p;
 
   ctx = new_omp_context (stmt, outer_ctx);
   scan_sharing_clauses (OMP_FOR_CLAUSES (stmt), ctx);
 
-  /* Make sure the iteration variable is private.  */
-  iter = TREE_OPERAND (OMP_FOR_INIT (stmt), 0);
-  if (!is_private_var (iter, ctx))
-    {
-      omp_context *pctx;
-      for (pctx = ctx; !is_parallel_ctx (pctx); pctx = pctx->outer)
-	continue;
-      install_var_private (iter, pctx);
-    }
-
   scan_omp (&OMP_FOR_PRE_BODY (stmt), ctx);
   scan_omp (&OMP_FOR_INIT (stmt), ctx);
   scan_omp (&OMP_FOR_COND (stmt), ctx);
@@ -823,7 +822,7 @@ scan_omp_nested (tree *stmt_p, omp_conte
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_variable_sized (decl))
 	    var_sized_list = tree_cons (NULL, decl, var_sized_list);
-	  OMP_CLAUSE_DECL (c) = install_var_private (decl, ctx);
+	  OMP_CLAUSE_DECL (c) = install_var_local (decl, ctx);
 	  break;
 
 	case OMP_CLAUSE_FIRSTPRIVATE:
@@ -852,7 +851,7 @@ scan_omp_nested (tree *stmt_p, omp_conte
      to do this as a separate pass, since we need the pointer and size
      decls installed first.  */
   for (c = var_sized_list; c ; c = TREE_CHAIN (c))
-    fixup_variable_sized (TREE_VALUE (c), ctx);
+    fixup_remapped_decl (TREE_VALUE (c), ctx);
 
   scan_omp (&OMP_BODY (stmt), ctx);
 
@@ -1122,21 +1121,10 @@ expand_rec_input_clauses (tree clauses, 
 			  omp_context *ctx)
 {
   tree_stmt_iterator diter;
-  tree c, dtor, copyin_seq, x;
+  tree c, dtor, copyin_seq, x, args, ptr;
   bool copyin_by_ref = false;
   int pass;
 
-  /* Resolve private references for Fortran.  Note that C++ disallows
-     private references, so there's no need to worry about CTORs.  */
-  for (c = ctx->block_vars; c; c = TREE_CHAIN (c))
-    if (DECL_INITIAL (c))
-      {
-	tree init = DECL_INITIAL (c);
-	DECL_INITIAL (c) = NULL;
-	init = build (MODIFY_EXPR, void_type_node, c, init);
-	gimplify_and_add (init, ilist);
-      }
-
   *dlist = alloc_stmt_list ();
   diter = tsi_start (*dlist);
   copyin_seq = NULL;
@@ -1155,6 +1143,7 @@ expand_rec_input_clauses (tree clauses, 
 
 	  switch (c_kind)
 	    {
+	    case OMP_CLAUSE_SHARED:
 	    case OMP_CLAUSE_PRIVATE:
 	    case OMP_CLAUSE_FIRSTPRIVATE:
 	    case OMP_CLAUSE_LASTPRIVATE:
@@ -1169,10 +1158,16 @@ expand_rec_input_clauses (tree clauses, 
 	  if (c_kind != OMP_CLAUSE_COPYIN)
 	    new_var = lookup_decl (var, ctx);
 
-	  if (is_variable_sized (var) && c_kind != OMP_CLAUSE_COPYIN)
+	  if (c_kind == OMP_CLAUSE_SHARED || c_kind == OMP_CLAUSE_COPYIN)
+	    {
+	      if (pass != 0)
+		continue;
+	    }
+	  /* For variable sized types, we need to allocate the actual
+	     storage here.  Call alloca and store the result in the pointer
+	     decl that we created elsewhere.  */
+	  else if (is_variable_sized (var))
 	    {
-	      tree t, args, ptr;
-
 	      if (pass == 0)
 		continue;
 
@@ -1181,21 +1176,63 @@ expand_rec_input_clauses (tree clauses, 
 	      ptr = TREE_OPERAND (ptr, 0);
 	      gcc_assert (DECL_P (ptr));
 
-	      t = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
-	      args = tree_cons (NULL, t, NULL);
-	      t = built_in_decls[BUILT_IN_ALLOCA];
-	      t = build_function_call_expr (t, args);
-	      t = fold_convert (TREE_TYPE (ptr), t);
-	      t = build2 (MODIFY_EXPR, void_type_node, ptr, t);
-	      gimplify_and_add (t, ilist);
+	      x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
+	      args = tree_cons (NULL, x, NULL);
+	      x = built_in_decls[BUILT_IN_ALLOCA];
+	      x = build_function_call_expr (x, args);
+	      x = fold_convert (TREE_TYPE (ptr), x);
+	      x = build2 (MODIFY_EXPR, void_type_node, ptr, x);
+	      gimplify_and_add (x, ilist);
+	    }
+	  /* For references that are being privatized for Fortran, allocate
+	     new backing storage for the new pointer variable.  This allows
+	     us to avoid changing all the code that expects a pointer to
+	     something that expects a direct variable.  Note that this
+	     doesn't apply to C++, since reference types are disallowed in
+	     data sharing clauses there.  */
+	  else if (is_reference (var))
+	    {
+	      if (pass == 0)
+		continue;
+
+	      x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
+	      if (TREE_CONSTANT (x))
+		{
+		  const char *name = NULL;
+		  if (DECL_NAME (var))
+		    name = IDENTIFIER_POINTER (DECL_NAME (new_var));
+
+		  x = create_tmp_var (TREE_TYPE (TREE_TYPE (new_var)), name);
+		  x = build_fold_addr_expr_with_type (x, TREE_TYPE (new_var));
+		}
+	      else
+		{
+		  args = tree_cons (NULL, x, NULL);
+		  x = built_in_decls[BUILT_IN_ALLOCA];
+		  x = build_function_call_expr (x, args);
+		  x = fold_convert (TREE_TYPE (new_var), x);
+		}
+
+	      x = build2 (MODIFY_EXPR, void_type_node, new_var, x);
+	      gimplify_and_add (x, ilist);
+
+	      new_var = build_fold_indirect_ref (new_var);
 	    }
 	  else if (pass != 0)
 	    continue;
-	  else if (is_reference (var))
-	    new_var = build_fold_indirect_ref (new_var);
 
 	  switch (TREE_CODE (c))
 	    {
+	    case OMP_CLAUSE_SHARED:
+	      /* Set up the DECL_VALUE_EXPR for shared variables now.  This
+		 needs to be delayed until after fixup_child_record_type so
+		 that we get the correct type during the dereference.  */
+	      by_ref = use_pointer_for_field (var, true);
+	      x = build_receiver_ref (var, by_ref, ctx);
+	      SET_DECL_VALUE_EXPR (new_var, x);
+	      DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	      break;
+
 	    case OMP_CLAUSE_LASTPRIVATE:
 	      if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
 		break;
@@ -1724,8 +1761,6 @@ expand_omp_parallel (tree *stmt_p, omp_c
 
   push_gimplify_context ();
 
-  expand_omp (&OMP_PARALLEL_BODY (*stmt_p), ctx);
-
   clauses = OMP_PARALLEL_CLAUSES (*stmt_p);
   bind = OMP_PARALLEL_BODY (*stmt_p);
   block = BIND_EXPR_BLOCK (bind);
@@ -1733,7 +1768,10 @@ expand_omp_parallel (tree *stmt_p, omp_c
   BIND_EXPR_BODY (bind) = alloc_stmt_list ();
 
   expand_rec_input_clauses (clauses, &BIND_EXPR_BODY (bind), &olist, ctx);
+
+  expand_omp (&body, ctx);
   append_to_statement_list (body, &BIND_EXPR_BODY (bind));
+
   expand_reduction_clauses (clauses, &BIND_EXPR_BODY (bind), ctx);
   append_to_statement_list (olist, &BIND_EXPR_BODY (bind));
   maybe_catch_exception (&BIND_EXPR_BODY (bind));
@@ -2586,8 +2624,6 @@ expand_omp_single (tree *stmt_p, omp_con
 
   push_gimplify_context ();
 
-  expand_omp (&OMP_SINGLE_BODY (single_stmt), ctx);
-
   block = make_node (BLOCK);
   bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, block);
   *stmt_p = bind;
@@ -2595,6 +2631,8 @@ expand_omp_single (tree *stmt_p, omp_con
   expand_rec_input_clauses (OMP_SINGLE_CLAUSES (single_stmt),
 			    &BIND_EXPR_BODY (bind), &dlist, ctx);
 
+  expand_omp (&OMP_SINGLE_BODY (single_stmt), ctx);
+
   if (ctx->record_type)
     expand_omp_single_copy (single_stmt, &BIND_EXPR_BODY (bind), ctx);
   else
Index: gcc/tree-nested.c
===================================================================
--- gcc/tree-nested.c	(revision 106281)
+++ gcc/tree-nested.c	(working copy)
@@ -89,9 +89,13 @@ struct nesting_info GTY ((chain_next ("%
   struct nesting_info *inner;
   struct nesting_info *next;
   
+  htab_t GTY ((param_is (struct var_map_elt))) field_map;
   htab_t GTY ((param_is (struct var_map_elt))) var_map;
+  bitmap suppress_expansion;
+
   tree context;
   tree new_local_var_chain;
+  tree debug_var_chain;
   tree frame_type;
   tree frame_decl;
   tree chain_field;
@@ -264,7 +268,7 @@ lookup_field_for_decl (struct nesting_in
   tree field;
 
   dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
+  slot = htab_find_slot (info->field_map, &dummy, insert);
   if (!slot)
     {
       gcc_assert (insert != INSERT);
@@ -714,7 +718,9 @@ static struct nesting_info *
 create_nesting_tree (struct cgraph_node *cgn)
 {
   struct nesting_info *info = ggc_calloc (1, sizeof (*info));
+  info->field_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
   info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
+  info->suppress_expansion = BITMAP_GGC_ALLOC ();
   info->context = cgn->decl;
 
   for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
@@ -790,17 +796,91 @@ get_frame_field (struct nesting_info *in
 	  tree field = get_chain_field (i);
 
 	  x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
-	  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+	  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
 	  x = init_tmp_var (info, x, tsi);
 	}
 
       x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
     }
 
-  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
   return x;
 }
 
+/* A subroutine of convert_nonlocal_reference.  Create a local variable
+   in the nested function with DECL_VALUE_EXPR set to reference the true
+   variable in the parent function.  This is used both for debug info 
+   and in OpenMP lowering.  */
+
+static tree
+get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
+{
+  struct var_map_elt *elt, dummy;
+  tree target_context;
+  struct nesting_info *i;
+  tree x, field, new_decl;
+  void **slot;
+
+  dummy.old = decl;
+  slot = htab_find_slot (info->var_map, &dummy, INSERT);
+  elt = *slot;
+
+  if (elt)
+    return elt->new;
+
+  target_context = decl_function_context (decl);
+
+  /* A copy of the code in get_frame_field, but without the temporaries.  */
+  if (info->context == target_context)
+    {
+      /* Make sure frame_decl gets created.  */
+      (void) get_frame_type (info);
+      x = info->frame_decl;
+      i = info;
+    }
+  else
+    {
+      x = get_chain_decl (info);
+      for (i = info->outer; i->context != target_context; i = i->outer)
+	{
+	  field = get_chain_field (i);
+	  x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+	  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+	}
+      x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+    }
+
+  field = lookup_field_for_decl (i, decl, INSERT);
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+  if (use_pointer_in_frame (decl))
+    x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+
+  /* ??? We should be remapping types as well, surely.  */
+  new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+
+  SET_DECL_VALUE_EXPR (new_decl, x);
+  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+
+  elt = ggc_alloc (sizeof (*elt));
+  elt->old = decl;
+  elt->new = new_decl;
+  *slot = elt;
+
+  TREE_CHAIN (new_decl) = info->debug_var_chain;
+  info->debug_var_chain = new_decl;
+
+  return new_decl;
+}
+
 /* Called via walk_function+walk_tree, rewrite all references to VAR
    and PARM_DECLs that belong to outer functions.
 
@@ -818,6 +898,7 @@ convert_nonlocal_reference (tree *tp, in
   struct nesting_info *info = wi->info;
   tree t = *tp;
   tree save_local_var_chain;
+  bitmap save_suppress;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -831,19 +912,23 @@ convert_nonlocal_reference (tree *tp, in
     case PARM_DECL:
       if (decl_function_context (t) != info->context)
 	{
-	  tree target_context = decl_function_context (t);
-	  struct nesting_info *i;
 	  tree x;
 	  wi->changed = true;
 
-	  for (i = info->outer; i->context != target_context; i = i->outer)
-	    continue;
-	  x = lookup_field_for_decl (i, t, INSERT);
-	  x = get_frame_field (info, target_context, x, &wi->tsi);
-	  if (use_pointer_in_frame (t))
+	  x = get_nonlocal_debug_decl (info, t);
+	  if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
 	    {
-	      x = init_tmp_var (info, x, &wi->tsi);
-	      x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+	      tree target_context = decl_function_context (t);
+	      struct nesting_info *i;
+	      for (i = info->outer; i->context != target_context; i = i->outer)
+		continue;
+	      x = lookup_field_for_decl (i, t, INSERT);
+	      x = get_frame_field (info, target_context, x, &wi->tsi);
+	      if (use_pointer_in_frame (t))
+		{
+		  x = init_tmp_var (info, x, &wi->tsi);
+		  x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+		}
 	    }
 
 	  if (wi->val_only)
@@ -946,6 +1031,7 @@ convert_nonlocal_reference (tree *tp, in
       break;
 
     case OMP_PARALLEL:
+      save_suppress = info->suppress_expansion;
       if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
 	{
 	  tree c;
@@ -963,13 +1049,16 @@ convert_nonlocal_reference (tree *tp, in
       if (info->new_local_var_chain)
 	declare_tmp_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t));
       info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
       break;
 
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
       convert_nonlocal_omp_clauses (&OMP_CLAUSES (t), wi);
       walk_body (convert_nonlocal_reference, info, &OMP_BODY (t));
+      info->suppress_expansion = save_suppress;
       break;
 
     case OMP_SECTION:
@@ -994,14 +1083,17 @@ convert_nonlocal_reference (tree *tp, in
 static bool
 convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
-  bool ret = false;
-  tree clause;
+  struct nesting_info *info = wi->info;
+  bool need_chain = false;
+  tree clause, decl;
   int dummy;
+  bitmap new_suppress;
 
-  while ((clause = *pclauses) != NULL)
-    {
-      bool remove = false;
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
 
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
       switch (TREE_CODE (clause))
 	{
 	case OMP_CLAUSE_PRIVATE:
@@ -1009,19 +1101,14 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYPRIVATE:
-	  wi->val_only = false;
-	  wi->changed = false;
-	  convert_nonlocal_reference (&OMP_CLAUSE_DECL (clause), &dummy, wi);
-	  /* FIXME -- need to retain the decl, with the value_expr set.  */
-	  gcc_assert (!wi->changed);
-	  break;
-
 	case OMP_CLAUSE_SHARED:
-	  wi->val_only = false;
-	  wi->changed = false;
-	  convert_nonlocal_reference (&OMP_CLAUSE_DECL (clause), &dummy, wi);
-	  ret |= wi->changed;
-	  remove = wi->changed;
+	  decl = OMP_CLAUSE_DECL (clause);
+	  if (decl_function_context (decl) != info->context)
+	    {
+	      bitmap_set_bit (new_suppress, DECL_UID (decl));
+	      OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+	      need_chain = true;
+	    }
 	  break;
 
 	case OMP_CLAUSE_SCHEDULE:
@@ -1044,14 +1131,60 @@ convert_nonlocal_omp_clauses (tree *pcla
 	default:
 	  gcc_unreachable ();
 	}
-
-      if (remove)
-	*pclauses = OMP_CLAUSE_CHAIN (clause);
-      else
-	pclauses = &OMP_CLAUSE_CHAIN (clause);
     }
 
-  return ret;
+  info->suppress_expansion = new_suppress;
+
+  return need_chain;
+}
+
+/* A subroutine of convert_local_reference.  Create a local variable
+   in the parent function with DECL_VALUE_EXPR set to reference the
+   field in FRAME.  This is used both for debug info and in OpenMP
+   lowering.  */
+
+static tree
+get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
+{
+  struct var_map_elt *elt, dummy;
+  tree x, new_decl;
+  void **slot;
+
+  dummy.old = decl;
+  slot = htab_find_slot (info->var_map, &dummy, INSERT);
+  elt = *slot;
+
+  if (elt)
+    return elt->new;
+
+  /* Make sure frame_decl gets created.  */
+  (void) get_frame_type (info);
+  x = info->frame_decl;
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+
+  new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+
+  SET_DECL_VALUE_EXPR (new_decl, x);
+  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+
+  elt = ggc_alloc (sizeof (*elt));
+  elt->old = decl;
+  elt->new = new_decl;
+  *slot = elt;
+
+  TREE_CHAIN (new_decl) = info->debug_var_chain;
+  info->debug_var_chain = new_decl;
+
+  return new_decl;
 }
 
 /* Called via walk_function+walk_tree, rewrite all references to VAR
@@ -1068,6 +1201,7 @@ convert_local_reference (tree *tp, int *
   tree t = *tp, field, x;
   bool save_val_only;
   tree save_local_var_chain;
+  bitmap save_suppress;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1093,7 +1227,9 @@ convert_local_reference (tree *tp, int *
 	    break;
 	  wi->changed = true;
 
-	  x = get_frame_field (info, info->context, field, &wi->tsi);
+	  x = get_local_debug_decl (info, t, field);
+	  if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+	    x = get_frame_field (info, info->context, field, &wi->tsi);
 
 	  if (wi->val_only)
 	    {
@@ -1176,6 +1312,7 @@ convert_local_reference (tree *tp, int *
       break;
 
     case OMP_PARALLEL:
+      save_suppress = info->suppress_expansion;
       if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
 	{
 	  tree c;
@@ -1193,13 +1330,16 @@ convert_local_reference (tree *tp, int *
       if (info->new_local_var_chain)
 	declare_tmp_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t));
       info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
       break;
 
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
       convert_local_omp_clauses (&OMP_CLAUSES (t), wi);
       walk_body (convert_local_reference, info, &OMP_BODY (t));
+      info->suppress_expansion = save_suppress;
       break;
 
     case OMP_SECTION:
@@ -1224,14 +1364,17 @@ convert_local_reference (tree *tp, int *
 static bool
 convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
-  bool ret = false;
-  tree clause;
+  struct nesting_info *info = wi->info;
+  bool need_frame = false;
+  tree clause, decl;
   int dummy;
+  bitmap new_suppress;
 
-  while ((clause = *pclauses) != NULL)
-    {
-      bool remove = false;
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
 
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
       switch (TREE_CODE (clause))
 	{
 	case OMP_CLAUSE_PRIVATE:
@@ -1239,19 +1382,20 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYPRIVATE:
-	  wi->val_only = false;
-	  wi->changed = false;
-	  convert_local_reference (&OMP_CLAUSE_DECL (clause), &dummy, wi);
-	  /* FIXME -- need to retain the decl, with the value_expr set.  */
-	  gcc_assert (!wi->changed);
-	  break;
-
 	case OMP_CLAUSE_SHARED:
-	  wi->val_only = false;
-	  wi->changed = false;
-	  convert_local_reference (&OMP_CLAUSE_DECL (clause), &dummy, wi);
-	  ret |= wi->changed;
-	  remove = wi->changed;
+	  decl = OMP_CLAUSE_DECL (clause);
+	  if (decl_function_context (decl) == info->context
+	      && !use_pointer_in_frame (decl))
+	    {
+	      tree field = lookup_field_for_decl (info, decl, NO_INSERT);
+	      if (field)
+		{
+		  bitmap_set_bit (new_suppress, DECL_UID (decl));
+		  OMP_CLAUSE_DECL (clause)
+		    = get_local_debug_decl (info, decl, field);
+		  need_frame = true;
+		}
+	    }
 	  break;
 
 	case OMP_CLAUSE_SCHEDULE:
@@ -1274,14 +1418,11 @@ convert_local_omp_clauses (tree *pclause
 	default:
 	  gcc_unreachable ();
 	}
-
-      if (remove)
-	*pclauses = OMP_CLAUSE_CHAIN (clause);
-      else
-	pclauses = &OMP_CLAUSE_CHAIN (clause);
     }
 
-  return ret;
+  info->suppress_expansion = new_suppress;
+
+  return need_frame;
 }
 
 /* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that 
@@ -1653,6 +1794,9 @@ finalize_nesting_tree_1 (struct nesting_
   if (root->new_local_var_chain)
     declare_tmp_vars (root->new_local_var_chain,
 		      DECL_SAVED_TREE (root->context));
+  if (root->debug_var_chain)
+    declare_tmp_vars (root->debug_var_chain,
+		      DECL_SAVED_TREE (root->context));
 
   /* Dump the translated tree function.  */
   dump_function (TDI_nested, root->context);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]