From df2c34fcbb12409aa976ade656525b85f2ca1c60 Mon Sep 17 00:00:00 2001
From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 2 May 2006 10:44:55 +0000
Subject: [PATCH] 	PR middle-end/27337 	* gimplify.c
 (gimplify_scan_omp_clauses): Handle INDIRECT_REF 	around RESULT_DECL for
 result passed by reference. 	(gimplify_expr): Call omp_notice_variable when
 RESULT_DECL is seen. 	* omp-low.c (use_pointer_for_field): Don't look at 
 DECL_HAS_VALUE_EXPR_P for RESULT_DECLs. 	(scan_omp_1): Call remap_decl
 on RESULT_DECLs. 	(lower_rec_input_clauses): Don't allocate VLA memory
 for the second 	time or var for passing by reference for 
 OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE clauses.  Allow creation of 
 TREE_ADDRESSABLE variables when passing by reference.

	* omp-low.c (dump_omp_region): Fix output formatting.
cp/
	* cp-gimplify.c (cxx_omp_privatize_by_reference): New function.
	* cp-tree.h (cxx_omp_privatize_by_reference): New prototype.
	* cp-objcp-common.h (LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE): Define.
testsuite/
	* g++.dg/gomp/pr27337-1.C: New test.
	* g++.dg/gomp/pr27337-2.C: New test.
libgomp/
	* testsuite/libgomp.c++/pr27337.C: New test.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@113456 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                           | 14 ++++
 gcc/cp/ChangeLog                        |  7 ++
 gcc/cp/cp-gimplify.c                    | 11 ++-
 gcc/cp/cp-objcp-common.h                |  2 +
 gcc/cp/cp-tree.h                        |  1 +
 gcc/gimplify.c                          | 17 +++++
 gcc/omp-low.c                           | 18 +++--
 gcc/testsuite/ChangeLog                 |  4 ++
 gcc/testsuite/g++.dg/gomp/pr27337-1.C   | 22 ++++++
 gcc/testsuite/g++.dg/gomp/pr27337-2.C   | 22 ++++++
 libgomp/ChangeLog                       |  5 ++
 libgomp/testsuite/libgomp.c++/pr27337.C | 91 +++++++++++++++++++++++++
 12 files changed, 208 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/gomp/pr27337-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/pr27337-2.C
 create mode 100644 libgomp/testsuite/libgomp.c++/pr27337.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9a0849a8794e..f9213111d183 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,19 @@
 2006-05-02  Jakub Jelinek  <jakub@redhat.com>
 
+	PR middle-end/27337
+	* gimplify.c (gimplify_scan_omp_clauses): Handle INDIRECT_REF
+	around RESULT_DECL for result passed by reference.
+	(gimplify_expr): Call omp_notice_variable when RESULT_DECL is seen.
+	* omp-low.c (use_pointer_for_field): Don't look at
+	DECL_HAS_VALUE_EXPR_P for RESULT_DECLs.
+	(scan_omp_1): Call remap_decl on RESULT_DECLs.
+	(lower_rec_input_clauses): Don't allocate VLA memory for the second
+	time or var for passing by reference for
+	OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE clauses.  Allow creation of
+	TREE_ADDRESSABLE variables when passing by reference.
+
+	* omp-low.c (dump_omp_region): Fix output formatting.
+
 	PR middle-end/27328
 	* omp-low.c (remove_exit_barrier): Handle NULL exit_bb.
 	(expand_omp_parallel): Likewise.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index bdc1f41268c8..937d5e80f153 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2006-05-02  Jakub Jelinek  <jakub@redhat.com>
+
+	PR middle-end/27337
+	* cp-gimplify.c (cxx_omp_privatize_by_reference): New function.
+	* cp-tree.h (cxx_omp_privatize_by_reference): New prototype.
+	* cp-objcp-common.h (LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE): Define.
+
 2006-04-30  Mark Mitchell  <mark@codesourcery.com>
 
 	PR c++/27094
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index be85ebb56f1d..4746103e6187 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1,6 +1,6 @@
 /* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c.
 
-   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Jason Merrill <jason@redhat.com>
 
 This file is part of GCC.
@@ -870,3 +870,12 @@ cxx_omp_clause_dtor (tree clause, tree decl)
 
   return ret;
 }
+
+/* True if OpenMP should privatize what this DECL points to rather
+   than the DECL itself.  */
+
+bool
+cxx_omp_privatize_by_reference (tree decl)
+{
+  return TREE_CODE (decl) == RESULT_DECL && DECL_BY_REFERENCE (decl);
+}
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 96e6eb699dca..65eb6aedfa36 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -161,5 +161,7 @@ extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t,
 #define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP cxx_omp_clause_assign_op
 #undef LANG_HOOKS_OMP_CLAUSE_DTOR
 #define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor
+#undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
+#define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
 
 #endif /* GCC_CP_OBJCP_COMMON */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1e3c1b7807db..2e5739a7eb68 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4267,6 +4267,7 @@ extern tree cxx_omp_clause_default_ctor		(tree, tree);
 extern tree cxx_omp_clause_copy_ctor		(tree, tree, tree);
 extern tree cxx_omp_clause_assign_op		(tree, tree, tree);
 extern tree cxx_omp_clause_dtor			(tree, tree);
+extern bool cxx_omp_privatize_by_reference	(tree);
 
 /* in tree.c */
 extern void lang_check_failed			(const char *, int,
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 3ee21d865afd..af3d92431284 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -4504,6 +4504,11 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel)
 	      remove = true;
 	      break;
 	    }
+	  /* Handle NRV results passed by reference.  */
+	  if (TREE_CODE (decl) == INDIRECT_REF
+	      && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
+	      && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
+	    OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
 	  omp_add_variable (ctx, decl, flags);
 	  if (TREE_CODE (c) == OMP_CLAUSE_REDUCTION
 	      && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@@ -4531,6 +4536,11 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel)
 	      remove = true;
 	      break;
 	    }
+	  /* Handle NRV results passed by reference.  */
+	  if (TREE_CODE (decl) == INDIRECT_REF
+	      && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL
+	      && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0)))
+	    OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0);
 	do_notice:
 	  if (outer_ctx)
 	    omp_notice_variable (outer_ctx, decl, true);
@@ -5558,6 +5568,13 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	  ret = gimplify_var_or_parm_decl (expr_p);
 	  break;
 
+	case RESULT_DECL:
+	  /* When within an OpenMP context, notice uses of variables.  */
+	  if (gimplify_omp_ctxp)
+	    omp_notice_variable (gimplify_omp_ctxp, *expr_p, true);
+	  ret = GS_ALL_DONE;
+	  break;
+
 	case SSA_NAME:
 	  /* Allow callbacks into the gimplifier during optimization.  */
 	  ret = GS_ALL_DONE;
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 62b715e37adb..f344e6933fbf 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -491,7 +491,7 @@ use_pointer_for_field (tree decl, bool shared_p)
 	 without analyzing the expression whether or not its location
 	 is accessible to anyone else.  In the case of nested parallel
 	 regions it certainly may be.  */
-      if (DECL_HAS_VALUE_EXPR_P (decl))
+      if (TREE_CODE (decl) != RESULT_DECL && DECL_HAS_VALUE_EXPR_P (decl))
 	return true;
 
       /* Do not use copy-in/copy-out for variables that have their
@@ -724,7 +724,7 @@ dump_omp_region (FILE *file, struct omp_region *region, int indent)
     }
     
   if (region->exit)
-    fprintf (file, "%*sbb: %d: OMP_RETURN\n", indent, "",
+    fprintf (file, "%*sbb %d: OMP_RETURN\n", indent, "",
 	     region->exit->index);
   else
     fprintf (file, "%*s[no exit marker]\n", indent, "");
@@ -1286,6 +1286,7 @@ scan_omp_1 (tree *tp, int *walk_subtrees, void *data)
     case VAR_DECL:
     case PARM_DECL:
     case LABEL_DECL:
+    case RESULT_DECL:
       if (ctx)
 	*tp = remap_decl (t, &ctx->cb);
       break;
@@ -1518,10 +1519,14 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
 	      break;
 	    case OMP_CLAUSE_SHARED:
 	    case OMP_CLAUSE_FIRSTPRIVATE:
-	    case OMP_CLAUSE_LASTPRIVATE:
 	    case OMP_CLAUSE_COPYIN:
 	    case OMP_CLAUSE_REDUCTION:
 	      break;
+	    case OMP_CLAUSE_LASTPRIVATE:
+	      if (pass != 0
+		  && OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
+		continue;
+	      break;
 	    default:
 	      continue;
 	    }
@@ -1564,7 +1569,8 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
 		 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.  */
+		 sharing clauses there, except for NRV optimized
+		 return values.  */
 	      if (pass == 0)
 		continue;
 
@@ -1575,7 +1581,9 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
 		  if (DECL_NAME (var))
 		    name = IDENTIFIER_POINTER (DECL_NAME (new_var));
 
-		  x = create_tmp_var (TREE_TYPE (TREE_TYPE (new_var)), name);
+		  x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
+					  name);
+		  gimple_add_tmp_var (x);
 		  x = build_fold_addr_expr_with_type (x, TREE_TYPE (new_var));
 		}
 	      else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b890b64302be..d5b92bb42584 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2006-05-02  Jakub Jelinek  <jakub@redhat.com>
 
+	PR middle-end/27337
+	* g++.dg/gomp/pr27337-1.C: New test.
+	* g++.dg/gomp/pr27337-2.C: New test.
+
 	PR middle-end/27328
 	* gcc.dg/gomp/pr27328.c: New test.
 
diff --git a/gcc/testsuite/g++.dg/gomp/pr27337-1.C b/gcc/testsuite/g++.dg/gomp/pr27337-1.C
new file mode 100644
index 000000000000..6c26070ab349
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr27337-1.C
@@ -0,0 +1,22 @@
+// PR middle-end/27337
+// { dg-do compile }
+
+struct S
+{
+  S ();
+  ~S ();
+  double &operator* () const;
+};
+
+S
+foo ()
+{
+  int i;
+  S ret;
+
+#pragma omp parallel for
+  for (i = 0; i < 2; i++)
+    *ret += i;
+
+  return ret;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr27337-2.C b/gcc/testsuite/g++.dg/gomp/pr27337-2.C
new file mode 100644
index 000000000000..d1ae4a139f22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr27337-2.C
@@ -0,0 +1,22 @@
+// PR middle-end/27337
+// { dg-do compile }
+
+struct S
+{
+  S ();
+  ~S ();
+  int i;
+};
+
+S
+foo ()
+{
+  int i;
+  S ret;
+
+#pragma omp parallel for firstprivate (ret) lastprivate (ret)
+  for (i = 0; i < 2; i++)
+    ret.i += i;
+
+  return ret;
+}
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 657b7ea04251..754d0f91df6b 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,8 @@
+2006-05-02  Jakub Jelinek  <jakub@redhat.com>
+
+	PR middle-end/27337
+	* testsuite/libgomp.c++/pr27337.C: New test.
+
 2006-04-26  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c/26171
diff --git a/libgomp/testsuite/libgomp.c++/pr27337.C b/libgomp/testsuite/libgomp.c++/pr27337.C
new file mode 100644
index 000000000000..c12154e02b66
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/pr27337.C
@@ -0,0 +1,91 @@
+// PR middle-end/27337
+// { dg-do run }
+
+#include <omp.h>
+
+extern "C" void abort (void);
+
+struct S
+{
+  S ();
+  ~S ();
+  S (const S &);
+  int i;
+};
+
+int n[3];
+
+S::S () : i(18)
+{
+  if (omp_get_thread_num () != 0)
+#pragma omp atomic
+    n[0]++;
+}
+
+S::~S ()
+{
+  if (omp_get_thread_num () != 0)
+#pragma omp atomic
+    n[1]++;
+}
+
+S::S (const S &x)
+{
+  if (x.i != 18)
+    abort ();
+  i = 118;
+  if (omp_get_thread_num () != 0)
+#pragma omp atomic
+    n[2]++;
+}
+
+S
+foo ()
+{
+  int i;
+  S ret;
+
+#pragma omp parallel for firstprivate (ret) lastprivate (ret) \
+			 schedule (static, 1) num_threads (4)
+  for (i = 0; i < 4; i++)
+    {
+      ret.i += omp_get_thread_num ();
+      // FIXME: The following barrier should be unnecessary.
+#pragma omp barrier
+    }
+
+  return ret;
+}
+
+S
+bar ()
+{
+  int i;
+  S ret;
+
+#pragma omp parallel for num_threads (4)
+  for (i = 0; i < 4; i++)
+#pragma omp atomic
+    ret.i += omp_get_thread_num () + 1;
+
+  return ret;
+}
+
+S x;
+
+int
+main (void)
+{
+  omp_set_dynamic (false);
+  x = foo ();
+  if (n[0] != 0 || n[1] != 3 || n[2] != 3)
+    abort ();
+  if (x.i != 118 + 3)
+    abort ();
+  x = bar ();
+  if (n[0] != 0 || n[1] != 3 || n[2] != 3)
+    abort ();
+  if (x.i != 18 + 0 + 1 + 2 + 3 + 4)
+    abort ();
+  return 0;
+}
-- 
GitLab