Consider the following OpenMP program:

    void foo (int a1) {}

    int
    main (void)
    {
      static int s1 = -41;
      int i1 = 11, i2;

      for (i2 = 1; i2 <= 2; i2++)
        {
          int pass = i2;
    #pragma omp parallel num_threads (2) firstprivate (i1)
          {
            foo (i1);
          }
          foo(pass);
        }
      foo (s1); foo (i2);
    }

At the moment, when debugging such a program, GDB is not able to find
and print the values of s1, i2, and pass.

My changes to omp-low.c and omp-expand.c, in conjunction with several
other patches, allow GDB to find and print these values.

This is the current behavior when debugging in GDB:

    (gdb) b 14
    Breakpoint 1 at 0x400617: file ex3.c, line 14.
    (gdb) run
    Starting program: /mesquite2/.ironwood2/omp-tests/k/ex3-trunk
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    [New Thread 0x7ffff73ca700 (LWP 32628)]

    Thread 1 "ex3-trunk" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14
    14              foo (i1);
    (gdb) p s1
    No symbol "s1" in current context.
    (gdb) p i1
    $1 = 11
    (gdb) p i2
    No symbol "i2" in current context.
    (gdb) p pass
    No symbol "pass" in current context.
    (gdb) c
    Continuing.
    [Switching to Thread 0x7ffff73ca700 (LWP 32628)]

    Thread 2 "ex3-trunk" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14
    14              foo (i1);
    (gdb) p s1
    No symbol "s1" in current context.
    (gdb) p i1
    $2 = 11
    (gdb) p i2
    No symbol "i2" in current context.
    (gdb) p pass
    No symbol "pass" in current context.
    (gdb) bt
    #0  main._omp_fn.0 () at ex3.c:14
    #1  0x00007ffff7bc4926 in gomp_thread_start (xdata=<optimized out>)
    at gcc/libgomp/team.c:122
    #2  0x00007ffff799761a in start_thread () from /lib64/libpthread.so.0
    #3  0x00007ffff76d159d in clone () from /lib64/libc.so.6

Note that GDB is unable to find s1, i2, or pass for either thread.

I show the backtrace for thread 2 because it's the more difficult case
to handle due to the stack trace stopping at clone().  The stack frame
for main(), which is where the variables of interest reside, is not a
part of this stack.

When we run this example using the patches associated with this change
along with several other patches, GDB's behavior looks like this:

    (gdb) b 14
    Breakpoint 1 at 0x400617: file ex3.c, line 14.
    (gdb) run
    Starting program: /mesquite2/.ironwood2/omp-tests/k/ex3-new
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    [New Thread 0x7ffff73ca700 (LWP 32643)]

    Thread 1 "ex3-new" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14
    14              foo (i1);
    (gdb) p s1
    $1 = -41
    (gdb) p i1
    $2 = 11
    (gdb) p i2
    $3 = 1
    (gdb) p pass
    $4 = 1
    (gdb) c
    Continuing.
    [Switching to Thread 0x7ffff73ca700 (LWP 32643)]

    Thread 2 "ex3-new" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14
    14              foo (i1);
    (gdb) p s1
    $5 = -41
    (gdb) p i1
    $6 = 11
    (gdb) p i2
    $7 = 1
    (gdb) p pass
    $8 = 1

I didn't show the stack here.  It's the same as before.  (I would,
however, like to be able to make GDB display a unified stack.)

Note that GDB is now able to find and print values for s1, i2, and
pass.

GCC constructs a new function for executing the parallel code.
The debugging information entry for this function is presently
placed at the same level as that of the function in which the
"#pragma omp parallel" directive appeared.

This is partial output from "readelf -v" for the (non-working) example
shown above:

 <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram)
    <2e>   DW_AT_external    : 1
    <2e>   DW_AT_name        : (indirect string, offset: 0x80): main
    <32>   DW_AT_decl_file   : 1
    <33>   DW_AT_decl_line   : 4
    <34>   DW_AT_prototyped  : 1
    <34>   DW_AT_type        : <0x9d>
    <38>   DW_AT_low_pc      : 0x400591
    <40>   DW_AT_high_pc     : 0x71
    <48>   DW_AT_frame_base  : 1 byte block: 9c         (DW_OP_call_frame_cfa)
    <4a>   DW_AT_GNU_all_tail_call_sites: 1
    <4a>   DW_AT_sibling     : <0x9d>
 <2><4e>: Abbrev Number: 3 (DW_TAG_variable)
    <4f>   DW_AT_name        : s1
    <52>   DW_AT_decl_file   : 1
    <53>   DW_AT_decl_line   : 6
    <54>   DW_AT_type        : <0x9d>
    <58>   DW_AT_location    : 9 byte block: 3 30 10 60 0 0 0 0 0       
(DW_OP_addr: 601030)
 ...
 <2><7c>: Abbrev Number: 4 (DW_TAG_lexical_block)
    <7d>   DW_AT_low_pc      : 0x4005a9
    <85>   DW_AT_high_pc     : 0x31
 <3><8d>: Abbrev Number: 5 (DW_TAG_variable)
    <8e>   DW_AT_name        : (indirect string, offset: 0x55): pass
    <92>   DW_AT_decl_file   : 1
    <93>   DW_AT_decl_line   : 11
    <94>   DW_AT_type        : <0x9d>
    <98>   DW_AT_location    : 2 byte block: 91 64      (DW_OP_fbreg: -28)
 ...
 <1><a4>: Abbrev Number: 7 (DW_TAG_subprogram)
    <a5>   DW_AT_name        : (indirect string, offset: 0x5a): main._omp_fn.0
    <a9>   DW_AT_prototyped  : 1
    <a9>   DW_AT_artificial  : 1
    <a9>   DW_AT_low_pc      : 0x400602
    <b1>   DW_AT_high_pc     : 0x21
    <b9>   DW_AT_frame_base  : 1 byte block: 9c         (DW_OP_call_frame_cfa)
    <bb>   DW_AT_GNU_all_tail_call_sites: 1
    <bb>   DW_AT_sibling     : <0xd5>
 <2><bf>: Abbrev Number: 8 (DW_TAG_formal_parameter)
    <c0>   DW_AT_type        : <0xed>
    <c4>   DW_AT_artificial  : 1
    <c4>   DW_AT_location    : 2 byte block: 91 58      (DW_OP_fbreg: -40)
 ...

The nesting level is indicated by the leading number in angle
brackets.  This shows that the DW_TAG_VARIABLE DIE for s1 is nested
within the DIE for main's DW_TAG_subprogram DIE.  Likewise, the
lexical block corresponding to the body of the for-loop is also nested
within main().  However, the DIES for main and main._omp_fun.0 are
both at level 1.

With my patches for omp-low.c and omp-expand.c, the readelf -w output
looks like this instead:

 <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram)
    <2e>   DW_AT_external    : 1
    <2e>   DW_AT_name        : (indirect string, offset: 0x80): main
    <32>   DW_AT_decl_file   : 1
    <33>   DW_AT_decl_line   : 4
    <34>   DW_AT_prototyped  : 1
    <34>   DW_AT_type        : <0xca>
    <38>   DW_AT_low_pc      : 0x400591
    <40>   DW_AT_high_pc     : 0x71
    <48>   DW_AT_frame_base  : 1 byte block: 9c         (DW_OP_call_frame_cfa)
    <4a>   DW_AT_GNU_all_tail_call_sites: 1
    <4a>   DW_AT_sibling     : <0xca>
 <2><4e>: Abbrev Number: 3 (DW_TAG_variable)
    <4f>   DW_AT_name        : s1
    <52>   DW_AT_decl_file   : 1
    <53>   DW_AT_decl_line   : 6
    <54>   DW_AT_type        : <0xca>
    <58>   DW_AT_location    : 9 byte block: 3 30 10 60 0 0 0 0 0       
(DW_OP_addr: 601030)
 <2><62>: Abbrev Number: 3 (DW_TAG_variable)
    <63>   DW_AT_name        : i1
    <66>   DW_AT_decl_file   : 1
    <67>   DW_AT_decl_line   : 7
    <68>   DW_AT_type        : <0xca>
    <6c>   DW_AT_location    : 2 byte block: 91 68      (DW_OP_fbreg: -24)
 <2><6f>: Abbrev Number: 3 (DW_TAG_variable)
    <70>   DW_AT_name        : i2
    <73>   DW_AT_decl_file   : 1
    <74>   DW_AT_decl_line   : 7
    <75>   DW_AT_type        : <0xca>
    <79>   DW_AT_location    : 2 byte block: 91 6c      (DW_OP_fbreg: -20)
 <2><7c>: Abbrev Number: 4 (DW_TAG_lexical_block)
    <7d>   DW_AT_low_pc      : 0x4005a9
    <85>   DW_AT_high_pc     : 0x31
 <3><8d>: Abbrev Number: 5 (DW_TAG_variable)
    <8e>   DW_AT_name        : (indirect string, offset: 0x55): pass
    <92>   DW_AT_decl_file   : 1
    <93>   DW_AT_decl_line   : 11
    <94>   DW_AT_type        : <0xca>
    <98>   DW_AT_location    : 2 byte block: 91 64      (DW_OP_fbreg: -28)
 <3><9b>: Abbrev Number: 6 (DW_TAG_subprogram)
    <9c>   DW_AT_name        : (indirect string, offset: 0x5a): main._omp_fn.0
    <a0>   DW_AT_prototyped  : 1
    <a0>   DW_AT_artificial  : 1
    <a0>   DW_AT_low_pc      : 0x400602
    <a8>   DW_AT_high_pc     : 0x21
    <b0>   DW_AT_frame_base  : 1 byte block: 9c         (DW_OP_call_frame_cfa)
    <b2>   DW_AT_GNU_all_tail_call_sites: 1
 <4><b2>: Abbrev Number: 7 (DW_TAG_formal_parameter)
    <b3>   DW_AT_type        : <0xe9>
    <b7>   DW_AT_artificial  : 1
    <b7>   DW_AT_location    : 2 byte block: 91 58      (DW_OP_fbreg: -40)
 <4><ba>: Abbrev Number: 3 (DW_TAG_variable)
    <bb>   DW_AT_name        : i1
    <be>   DW_AT_decl_file   : 1
    <bf>   DW_AT_decl_line   : 7
    <c0>   DW_AT_type        : <0xca>
    <c4>   DW_AT_location    : 2 byte block: 91 6c      (DW_OP_fbreg: -20)

This time, note that the lexical block for the for-loop is still nested
within main().  The DIE for main._omp_fn.0 is nested within that lexical
block.

This nesting enables GDB to find variables which ought to be in scope.

(Obviously, there's some extra work required for finding variables
which reside on the stack in a different thread.  That's handled in
patches to GDB and to libgomp.)

gcc/ChangeLog:
    
        * omp-low.c (create_omp_child_function): Set DECL_CONTEXT
        of child function to that of source function.
        * omp-expand.c (expand_parallel_call): Add child function
        to var chain in block from which child function originated.

diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 5c48b78..7029951 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -667,6 +667,25 @@ expand_parallel_call (struct omp_region *region, 
basic_block bb,
   tree child_fndecl = gimple_omp_parallel_child_fn (entry_stmt);
   t2 = build_fold_addr_expr (child_fndecl);
 
+  if (gimple_block (entry_stmt) != NULL_TREE
+      && TREE_CODE (gimple_block (entry_stmt)) == BLOCK)
+    {
+      tree b = BLOCK_SUPERCONTEXT (gimple_block (entry_stmt));
+
+      /* Add child_fndecl to var chain of the supercontext of the
+        block corresponding to entry_stmt.  This ensures that debug
+        info for the outlined function will be emitted for the correct
+        lexical scope.  */
+      if (b != NULL_TREE && TREE_CODE (b) == BLOCK)
+       {
+         tree *tp;
+
+         for (tp = &BLOCK_VARS (b); *tp; tp = &DECL_CHAIN (*tp))
+           ;
+         *tp = child_fndecl;
+        }
+    }
+
   vec_alloc (args, 4 + vec_safe_length (ws_args));
   args->quick_push (t2);
   args->quick_push (t1);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 9cc2996..601d1b4 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1626,7 +1626,7 @@ create_omp_child_function (omp_context *ctx, bool 
task_copy)
   TREE_PUBLIC (decl) = 0;
   DECL_UNINLINABLE (decl) = 1;
   DECL_EXTERNAL (decl) = 0;
-  DECL_CONTEXT (decl) = NULL_TREE;
+  DECL_CONTEXT (decl) = ctx->cb.src_fn;
   DECL_INITIAL (decl) = make_node (BLOCK);
   BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
   if (omp_maybe_offloaded_ctx (ctx))

Reply via email to