Page MenuHomePhabricator

[clang][OpenMP][DebugInfo] Debug support for variables in containing scope of OMP constructs
Needs ReviewPublic

Authored by alok on May 4 2022, 11:08 PM.

Details

Summary

In case of OpenMP, compilers generate encapsulates code present in
OpenMP construct to artificial functions. This is done to apply parallelism
to block of code. In context of these blocks, currently containing scope
variables are not accessible. This is due to new artificial function DIE being
in global scope.
As from user point of view, containing scope is same lexical scope, there
must be correct DIE hierarchy for artificial functions, which should be child
of containing scope.
Please consider below testcase.

 1  #include <stdio.h>
 2  #include <stdlib.h>
 3
 4  int global_var1;
 5  int global_var2 = 99;
 6  int foo(int n) {
 7    int same_var = 5;
 8    int other_var = 21;
 9    int share = 9, priv, i;
10    global_var1 = 99;
11
12    if (n < 2)
13      return n;
14    else {
15      int same_var = rand() % 5;
16      int local_var = 31;
17  #pragma omp parallel for
18      for (i = 0; i < n; i++) {
19        share += i;  // <-------------- (A)
20      }
21      return share;
22    }
23  }
24
25  int main() {
26    int n = 10;
27    printf("foo(%d) = %d\n", n, foo(n));
28    return 0;
29  }

Please consider the line# 19, user expects variables "same_var", "local_var", "other_var" to be
accessible inside debugger but which is not possible.

(gdb) p same_var
No symbol "same_var" in current context.
(gdb) p other_var
No symbol "other_var" in current context.
(gdb) p local_var
No symbol "local_var" in current context.

After current patch.

(gdb) thr 1
[Switching to thread 1 (Thread 0x7ffff7c1c400 (LWP 17992))]
#0  .omp_outlined._debug__ (.global_tid.=0x7fffffffdad0, .bound_tid.=0x7fffffffdac8, n=@0x7fffffffdf18: 10, share=@0x7fffffffdf0c: 9) at 1.c:19
19            share += i;
(gdb) p same_var
$1 = 3
(gdb) p local_var
$2 = 31
(gdb) p other_var
$3 = 21

Diff Detail

Unit TestsFailed

TimeTest
60,020 msx64 debian > libFuzzer.libFuzzer::fuzzer-leak.test
Script: -- : 'RUN: at line 3'; /var/lib/buildkite-agent/builds/llvm-project/build/./bin/clang --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/var/lib/buildkite-agent/builds/llvm-project/compiler-rt/lib/fuzzer -m64 /var/lib/buildkite-agent/builds/llvm-project/compiler-rt/test/fuzzer/LeakTest.cpp -o /var/lib/buildkite-agent/builds/llvm-project/build/projects/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/fuzzer-leak.test.tmp-LeakTest
60,020 msx64 debian > libFuzzer.libFuzzer::minimize_crash.test
Script: -- : 'RUN: at line 1'; /var/lib/buildkite-agent/builds/llvm-project/build/./bin/clang --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/var/lib/buildkite-agent/builds/llvm-project/compiler-rt/lib/fuzzer -m64 /var/lib/buildkite-agent/builds/llvm-project/compiler-rt/test/fuzzer/NullDerefTest.cpp -o /var/lib/buildkite-agent/builds/llvm-project/build/projects/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/minimize_crash.test.tmp-NullDerefTest
60,040 msx64 debian > libFuzzer.libFuzzer::out-of-process-fuzz.test
Script: -- : 'RUN: at line 2'; rm -rf /var/lib/buildkite-agent/builds/llvm-project/build/projects/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/out-of-process-fuzz.test.tmp && mkdir /var/lib/buildkite-agent/builds/llvm-project/build/projects/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/out-of-process-fuzz.test.tmp
60,020 msx64 debian > libFuzzer.libFuzzer::value-profile-load.test
Script: -- : 'RUN: at line 2'; /var/lib/buildkite-agent/builds/llvm-project/build/./bin/clang --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/var/lib/buildkite-agent/builds/llvm-project/compiler-rt/lib/fuzzer -m64 /var/lib/buildkite-agent/builds/llvm-project/compiler-rt/test/fuzzer/LoadTest.cpp -fsanitize-coverage=trace-gep -o /var/lib/buildkite-agent/builds/llvm-project/build/projects/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/value-profile-load.test.tmp-LoadTest

Event Timeline

alok created this revision.May 4 2022, 11:08 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 4 2022, 11:08 PM
alok requested review of this revision.May 4 2022, 11:08 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald Transcript
alok updated this revision to Diff 427237.May 5 2022, 1:22 AM

re-based.

alok updated this revision to Diff 428322.May 10 2022, 2:47 AM

Re-based.

bwyma added a subscriber: bwyma.May 10 2022, 5:49 AM

If the parent function is inlined into multiple callers, is the outlined subprogram scope treated like any other nested lexical scope and duplicated?
If the outlined subprogram scope is duplicated when inlined, how will retained nodes on the outlined subprogram be handled in this case?
Does CodeViewDebug handle the nested subprogram scoping?
Can you add a test which validates the nested scoping is correct in the DWARF emission (covering the non-clang part of this patch)?

krisb added a subscriber: krisb.May 17 2022, 3:11 AM
krisb added inline comments.
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
689

In case of compiling optimized code with inlining enabled, the Scope may be either a scope of an inlined instance (which may appear multiple times), an abstract scope or a concrete out-of-line scope. All of them will match a single ScopeNode, so this will override the map's value multiple times and getDIE() will likely return something that one may not expect.
I've been working on patches that make possible for local types, imports and static variables to be scoped in a lexical block, see D125693 for backend-related changes. May be you could find something useful there (see DwarfCompileUnit::getOrCreateLexicalBlockDIE() and DwarfCompileUnit::getOrCreateContextDIE()) or could help to review the patches.