[gomp] Fix nested function calls in OMP directive bodies

Jakub Jelinek jakub@redhat.com
Thu Dec 1 11:19:00 GMT 2005


Hi!

The following patch fixes the attached testcases.
convert_call_expr wasn't discovering embedded nested fn calls, which lead
either to ICEs if they were to be inlined, or to runtime crashes when
chain reg contained garbage.

OMP_ATOMIC nor OMP_CLAUSE_{IF,NUM_THREADS,SCHEDULE}'s expressions don't need
to be walked, since they were already gimplified in the previous pass.

Ok for gomp?

I haven't intentionally included OMP_PARALLEL case there.  They are still
broken, but will require orders of magnitude more work.
In OMP_PARALLELs bodies I think we need to create a new FRAME structure,
remap all nested fn calls to use that as TREE_OPERAND (call, 2)
and initialize the FRAME structure somehow, depending on which variables
are supposed to be shared or private.  While in C we are not bound by
the OpenMP standard, in Fortran nested functions are part of the standard
and therefore we'll need to figure out the exact sharing rules and what not.

2005-12-01  Jakub Jelinek  <jakub@redhat.com>

	* tree-nested.c (convert_call_expr): Call walk_body on OMP_BODY for
	OpenMP directives.

	* testsuite/libgomp.fortran/nestedfn2.f90: New test.
	* testsuite/libgomp.c/nestedfn-3.c: New test.

--- gcc/tree-nested.c.jj	2005-10-31 23:36:11.000000000 +0100
+++ gcc/tree-nested.c	2005-12-01 12:00:26.000000000 +0100
@@ -1638,6 +1638,15 @@ convert_call_expr (tree *tp, int *walk_s
       *walk_subtrees = 1;
       break;
 
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+      walk_body (convert_call_expr, info, &OMP_BODY (t));
+      break;
+
     default:
       break;
     }
--- libgomp/testsuite/libgomp.fortran/nestedfn2.f90.jj	2005-12-01 10:41:51.000000000 +0100
+++ libgomp/testsuite/libgomp.fortran/nestedfn2.f90	2005-12-01 10:59:05.000000000 +0100
@@ -0,0 +1,34 @@
+! { dg-do run }
+
+  integer :: i
+  common /c/ i
+  i = -1
+!$omp parallel shared (i) num_threads (4)
+  call test1
+!$omp end parallel
+end
+subroutine test1
+  integer :: vari
+  call test2
+  call test3
+contains
+  subroutine test2
+    use omp_lib
+    integer :: i
+    common /c/ i
+!$omp single
+    i = omp_get_thread_num ()
+    call test4
+!$omp end single copyprivate (vari)
+  end subroutine test2
+  subroutine test3
+    integer :: i
+    common /c/ i
+    if (i .lt. 0 .or. i .ge. 4) call abort
+    if (i + 10 .ne. vari) call abort
+  end subroutine test3
+  subroutine test4
+    use omp_lib
+    vari = omp_get_thread_num () + 10
+  end subroutine test4
+end subroutine test1
--- libgomp/testsuite/libgomp.c/nestedfn-3.c.jj	2005-12-01 10:43:32.000000000 +0100
+++ libgomp/testsuite/libgomp.c/nestedfn-3.c	2005-12-01 11:01:31.000000000 +0100
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+
+#include <omp.h>
+
+extern void abort (void);
+
+int
+main (void)
+{
+  int i = 5, l = 0;
+  int foo (void) { return i == 6; }
+  int bar (void) { return i - 3; }
+
+  omp_set_dynamic (0);
+
+#pragma omp parallel if (foo ()) num_threads (bar ()) reduction (|:l)
+  if (omp_get_num_threads () != 1)
+    l = 1;
+
+  i++;
+
+#pragma omp parallel if (foo ()) num_threads (bar ()) reduction (|:l)
+  if (omp_get_num_threads () != 3)
+    l = 1;
+
+  i++;
+
+#pragma omp master
+  if (bar () != 4)
+    abort ();
+
+#pragma omp single
+  {
+    if (foo ())
+      abort ();
+    i--;
+    if (! foo ())
+      abort ();
+  }
+
+  if (l)
+    abort ();
+
+  i = 8;
+#pragma omp atomic
+  l += bar ();
+
+  if (l != 5)
+    abort ();
+
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list