Patchwork Improve OpenMP debug info for threadprivate vars and shared local statics

login
register
mail settings
Submitter Jakub Jelinek
Date July 22, 2010, 4:25 p.m.
Message ID <20100722162552.GA18378@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/59602/
State New
Headers show

Comments

Jakub Jelinek - July 22, 2010, 4:25 p.m.
Hi!

On testcases like:

program foo
  integer :: x, y
  common /blk/ x, y
  !$omp threadprivate (/blk/)
  x = 6
  y = 7
  !$omp parallel
  x = 8
  y = 9
  x = x + 1
  y = y + 1
  !$omp end parallel
end

and

int
main (void)
{
  static int thr;
  static int svar1, svar2;
  int avar1 = 0, avar2 = 0;
#pragma omp threadprivate (thr)
  thr = 18;
  thr++;
  svar1++;
  svar2++;
  avar1++;
  avar2++;
#pragma omp parallel shared(svar2, avar2)
  {
    thr = 16;
    thr++;
    {
      int vv = 6;
      vv++;
      #pragma omp atomic
        svar2++;
    }
    #pragma omp atomic
    avar2++;
  }
  svar1++;
  avar1++;
  return 0;
}

x and y in the first testcase and thr and svar2 aren't visible in the
debugger when in *omp_fn* function.  While in theory it should be possible
for the debugger to look at the containing function in the initial thread
(*omp_fn* is DW_AT_artificial) and find those vars there, that can take a
long time before it is implemented in gdb.

The following patch adds the referenced fn local threadprivate and statics
to the *omp_fn* DW_TAG_subprogram too.

Do you think that is a good idea?

Bootstrapped/regtested on x86_64-linux and i686-linux.

2010-07-22  Jakub Jelinek  <jakub@redhat.com>

	* gimplify.c (enum gimplify_omp_var_data): Add
	GOVD_THREADPRIVATE_WARNED.
	(gimplify_bind_expr): Add GOVD_LOCAL | GOVD_SEEN even for global vars.
	(omp_notice_threadprivate_variable): Note used threadprivate vars
	with current function's context in shared clauses.
	(gimplify_adjust_omp_clauses_1): Allow globals with current function's
	context in taskreg shared clause.
	* omp-low.c (lower_rec_input_clauses): For function-local is_global_var
	VAR_DECLs in shared clauses add a decl copy with DECL_VALUE_EXPR
	pointing to the original.

	* trans-openmp.c (gfc_omp_private_debug_clause): Return false for
	threadprivate decls.

	* gcc.dg/gomp/tls-3.c: New test.


	Jakub
Richard Henderson - July 22, 2010, 4:38 p.m.
On 07/22/2010 09:25 AM, Jakub Jelinek wrote:
> Do you think that is a good idea?
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux.
> 
> 2010-07-22  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* gimplify.c (enum gimplify_omp_var_data): Add
> 	GOVD_THREADPRIVATE_WARNED.
> 	(gimplify_bind_expr): Add GOVD_LOCAL | GOVD_SEEN even for global vars.
> 	(omp_notice_threadprivate_variable): Note used threadprivate vars
> 	with current function's context in shared clauses.
> 	(gimplify_adjust_omp_clauses_1): Allow globals with current function's
> 	context in taskreg shared clause.
> 	* omp-low.c (lower_rec_input_clauses): For function-local is_global_var
> 	VAR_DECLs in shared clauses add a decl copy with DECL_VALUE_EXPR
> 	pointing to the original.
> 
> 	* trans-openmp.c (gfc_omp_private_debug_clause): Return false for
> 	threadprivate decls.
> 
> 	* gcc.dg/gomp/tls-3.c: New test.

Yes, I think it's a good idea.

Ok.


r~
Roland McGrath - July 22, 2010, 7:19 p.m.
> x and y in the first testcase and thr and svar2 aren't visible in the
> debugger when in *omp_fn* function.  While in theory it should be possible
> for the debugger to look at the containing function in the initial thread
> (*omp_fn* is DW_AT_artificial) and find those vars there, that can take a
> long time before it is implemented in gdb.
> 
> The following patch adds the referenced fn local threadprivate and statics
> to the *omp_fn* DW_TAG_subprogram too.

IMHO it would be better to do it without such duplication.  I think we
can beat the support out of the gdb people well enough, if the "proper"
indirect representations of all the info are there.

With 4.4.4(RH)-10, I see:

<subprogram name="main.omp_fn.0" prototyped=1 artificial=1 low_pc=0x4005e0 high_pc=0x4005fc frame_base={locexpr}>

Shouldn't that have static_link to refer to main as a nested function
would?  If it did, wouldn't that make the debugger handle it as it
should already handle nested functions?

These following questions are tangential, but it's the first time I've
really looked at -fopenmp DWARF output.

The name "main.omp_fn.0" is not a source identifier.  Should it really
be there in name?  IMHO it seems more proper for that to have only
artificial=true, linkage_name="main.omp_fn.0", and no name.  (Perhaps
linkage_name is not useful or appropriate since it's not DW_AT_external.)

Similarly: 

   <formal_parameter name=".omp_data_i" type="#ref1" artificial=1 location={locexpr}/>

Should that really have a name?  As it stands, the debugger is going to
present ".omp_data_i" as a resolvable identifier in this scope, as it
would for any other artifical parameter (such as C++ "this").

Next:

  <structure_type ref="ref4" name=".omp_data_s.10" byte_size=0x8>

This needs artificial=true too.  Again, it seems quite questionable
whether the non-source name should appear at all.  AIUI, this sort of
thing is exactly what DW_AT_description is for.


Thanks,
Roland
Tom Tromey - July 23, 2010, 9:03 p.m.
>>>>> "Roland" == Roland McGrath <roland@redhat.com> writes:

Roland> IMHO it would be better to do it without such duplication.  I
Roland> think we can beat the support out of the gdb people well enough,
Roland> if the "proper" indirect representations of all the info are
Roland> there.

Please file a bug in gdb bugzilla with all the details.

Tom

Patch

--- gcc/fortran/trans-openmp.c.jj	2010-07-15 14:35:35.000000000 +0200
+++ gcc/fortran/trans-openmp.c	2010-07-22 12:02:26.000000000 +0200
@@ -352,6 +352,18 @@  gfc_omp_disregard_value_expr (tree decl,
 bool
 gfc_omp_private_debug_clause (tree decl, bool shared)
 {
+  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+    {
+      if (DECL_THREAD_LOCAL_P (decl))
+	return false;
+      if (DECL_HAS_VALUE_EXPR_P (decl))
+	{
+	  tree value = get_base_address (DECL_VALUE_EXPR (decl));
+	  if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value))
+	    return false;
+	}
+    }
+
   if (GFC_DECL_CRAY_POINTEE (decl))
     return true;
 
--- gcc/gimplify.c.jj	2010-07-16 17:55:08.000000000 +0200
+++ gcc/gimplify.c	2010-07-22 14:45:08.000000000 +0200
@@ -64,6 +64,7 @@  enum gimplify_omp_var_data
   GOVD_LOCAL = 128,
   GOVD_DEBUG_PRIVATE = 256,
   GOVD_PRIVATE_OUTER_REF = 512,
+  GOVD_THREADPRIVATE_WARNED = 1024,
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL)
 };
@@ -1140,7 +1141,7 @@  gimplify_bind_expr (tree *expr_p, gimple
 	  struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
 
 	  /* Mark variable as local.  */
-	  if (ctx && !is_global_var (t)
+	  if (ctx
 	      && (! DECL_SEEN_IN_BIND_EXPR_P (t)
 		  || splay_tree_lookup (ctx->variables,
 					(splay_tree_key) t) == NULL))
@@ -5520,17 +5521,36 @@  omp_notice_threadprivate_variable (struc
 {
   splay_tree_node n;
 
-  if (ctx->region_type != ORT_UNTIED_TASK)
+  while (ctx && ctx->region_type == ORT_WORKSHARE)
+    {
+      n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
+      if (n != NULL)
+	{
+	  gcc_assert (n->value & GOVD_LOCAL);
+	  return false;
+	}
+      ctx = ctx->outer_context;
+    }
+  if (ctx == NULL)
     return false;
+
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
   if (n == NULL)
+    n = splay_tree_insert (ctx->variables, (splay_tree_key)decl,
+			   DECL_CONTEXT (decl) == current_function_decl
+			   ? GOVD_SHARED | GOVD_SEEN : 0);
+  if (ctx->region_type == ORT_UNTIED_TASK
+      && (n->value & GOVD_THREADPRIVATE_WARNED) == 0)
     {
-      error ("threadprivate variable %qE used in untied task", DECL_NAME (decl));
+      error ("threadprivate variable %qE used in untied task",
+	     DECL_NAME (decl));
       error_at (ctx->location, "enclosing task");
-      splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0);
+      n->value |= GOVD_THREADPRIVATE_WARNED;
     }
   if (decl2)
-    splay_tree_insert (ctx->variables, (splay_tree_key)decl2, 0);
+    splay_tree_insert (ctx->variables, (splay_tree_key)decl2,
+		       DECL_CONTEXT (decl2) == current_function_decl
+		       ? GOVD_SHARED | GOVD_SEEN : 0);
   return false;
 }
 
@@ -5958,7 +5978,9 @@  gimplify_adjust_omp_clauses_1 (splay_tre
 		break;
 	      ctx = ctx->outer_context;
 	    }
-	  if (ctx == NULL)
+	  if (ctx == NULL
+	      && (DECL_CONTEXT (decl) != current_function_decl
+		  || gimplify_omp_ctxp->region_type == ORT_WORKSHARE))
 	    return 0;
 	}
       code = OMP_CLAUSE_SHARED;
--- gcc/omp-low.c.jj	2010-07-16 17:55:08.000000000 +0200
+++ gcc/omp-low.c	2010-07-22 14:09:33.000000000 +0200
@@ -2248,6 +2248,17 @@  lower_rec_input_clauses (tree clauses, g
 		continue;
 	      break;
 	    case OMP_CLAUSE_SHARED:
+	      if (pass == 0
+		  && is_global_var (OMP_CLAUSE_DECL (c))
+		  && (DECL_CONTEXT (OMP_CLAUSE_DECL (c))
+		      == current_function_decl)
+		  && is_taskreg_ctx (ctx)
+		  && !DECL_IGNORED_P (OMP_CLAUSE_DECL (c)))
+		{
+		  new_var = omp_copy_decl_1 (OMP_CLAUSE_DECL (c), ctx);
+		  SET_DECL_VALUE_EXPR (new_var, OMP_CLAUSE_DECL (c));
+		  DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+		}
 	      if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
 		{
 		  gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
--- gcc/testsuite/gcc.dg/gomp/tls-3.c.jj	2010-07-22 15:48:41.000000000 +0200
+++ gcc/testsuite/gcc.dg/gomp/tls-3.c	2010-07-22 15:48:47.000000000 +0200
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+
+int thr;
+#pragma omp threadprivate(thr)
+
+void
+foo (void)
+{
+  #pragma omp task untied	/* { dg-error "enclosing task" } */
+  {
+    static int thr2;
+    #pragma omp threadprivate(thr2)
+    static int thr3;
+    #pragma omp threadprivate(thr3)
+    thr++;	/* { dg-error "used in untied task" } */
+    thr2++;	/* { dg-error "used in untied task" } */
+    thr++;
+    thr2++;
+  }
+}