Skip to content

Commit 5eb2718

Browse files
committed
[clang][OpenMP][DebugInfo] Debug support for variables in shared clause of OpenMP task construct
Currently variables appearing inside shared clause of OpenMP task construct are not visible inside lldb debugger. After the current patch, lldb is able to show the variable ``` * thread #1, name = 'a.out', stop reason = breakpoint 1.1 frame #0: 0x0000000000400934 a.out`.omp_task_entry. [inlined] .omp_outlined.(.global_tid.=0, .part_id.=0x000000000071f0d0, .privates.=0x000000000071f0e8, .copy_fn.=(a.out`.omp_task_privates_map. at testshared.cxx:8), .task_t.=0x000000000071f0c0, __context=0x000000000071f0f0) at testshared.cxx:10:34 7 else { 8 #pragma omp task shared(svar) firstprivate(n) 9 { -> 10 printf("Task svar = %d\n", svar); 11 printf("Task n = %d\n", n); 12 svar = fib(n - 1); 13 } (lldb) p svar (int) $0 = 9 ``` Reviewed By: djtodoro Differential Revision: https://reviews.llvm.org/D115510
1 parent a9bb97e commit 5eb2718

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

clang/lib/CodeGen/CGStmtOpenMP.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
#include "clang/AST/StmtVisitor.h"
2525
#include "clang/Basic/OpenMPKinds.h"
2626
#include "clang/Basic/PrettyStackTrace.h"
27+
#include "llvm/BinaryFormat/Dwarf.h"
2728
#include "llvm/Frontend/OpenMP/OMPConstants.h"
2829
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
2930
#include "llvm/IR/Constants.h"
31+
#include "llvm/IR/DebugInfoMetadata.h"
3032
#include "llvm/IR/Instructions.h"
33+
#include "llvm/IR/Metadata.h"
3134
#include "llvm/Support/AtomicOrdering.h"
3235
using namespace clang;
3336
using namespace CodeGen;
@@ -4431,6 +4434,53 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
44314434
UntiedLocalVars;
44324435
// Set proper addresses for generated private copies.
44334436
OMPPrivateScope Scope(CGF);
4437+
// Generate debug info for variables present in shared clause.
4438+
if (auto *DI = CGF.getDebugInfo()) {
4439+
llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields =
4440+
CGF.CapturedStmtInfo->getCaptureFields();
4441+
llvm::Value *ContextValue = CGF.CapturedStmtInfo->getContextValue();
4442+
if (CaptureFields.size() && ContextValue) {
4443+
unsigned CharWidth = CGF.getContext().getCharWidth();
4444+
// The shared variables are packed together as members of structure.
4445+
// So the address of each shared variable can be computed by adding
4446+
// offset of it (within record) to the base address of record. For each
4447+
// shared variable, debug intrinsic llvm.dbg.declare is generated with
4448+
// appropriate expressions (DIExpression).
4449+
// Ex:
4450+
// %12 = load %struct.anon*, %struct.anon** %__context.addr.i
4451+
// call void @llvm.dbg.declare(metadata %struct.anon* %12,
4452+
// metadata !svar1,
4453+
// metadata !DIExpression(DW_OP_deref))
4454+
// call void @llvm.dbg.declare(metadata %struct.anon* %12,
4455+
// metadata !svar2,
4456+
// metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref))
4457+
for (auto It = CaptureFields.begin(); It != CaptureFields.end(); ++It) {
4458+
const VarDecl *SharedVar = It->first;
4459+
RecordDecl *CaptureRecord = It->second->getParent();
4460+
const ASTRecordLayout &Layout =
4461+
CGF.getContext().getASTRecordLayout(CaptureRecord);
4462+
unsigned Offset =
4463+
Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth;
4464+
(void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
4465+
CGF.Builder, false);
4466+
llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back();
4467+
// Get the call dbg.declare instruction we just created and update
4468+
// its DIExpression to add offset to base address.
4469+
if (auto DDI = dyn_cast<llvm::DbgVariableIntrinsic>(&Last)) {
4470+
SmallVector<uint64_t, 8> Ops;
4471+
// Add offset to the base address if non zero.
4472+
if (Offset) {
4473+
Ops.push_back(llvm::dwarf::DW_OP_plus_uconst);
4474+
Ops.push_back(Offset);
4475+
}
4476+
Ops.push_back(llvm::dwarf::DW_OP_deref);
4477+
auto &Ctx = DDI->getContext();
4478+
llvm::DIExpression *DIExpr = llvm::DIExpression::get(Ctx, Ops);
4479+
Last.setOperand(2, llvm::MetadataAsValue::get(Ctx, DIExpr));
4480+
}
4481+
}
4482+
}
4483+
}
44344484
llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> FirstprivatePtrs;
44354485
if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
44364486
!Data.LastprivateVars.empty() || !Data.PrivateLocals.empty()) {

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,11 @@ class CodeGenFunction : public CodeGenTypeCache {
459459
/// Get the name of the capture helper.
460460
virtual StringRef getHelperName() const { return "__captured_stmt"; }
461461

462+
/// Get the CaptureFields
463+
llvm::SmallDenseMap<const VarDecl *, FieldDecl *> getCaptureFields() {
464+
return CaptureFields;
465+
}
466+
462467
private:
463468
/// The kind of captured statement being generated.
464469
CapturedRegionKind Kind;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// This testcase checks emission of debug info for variables
2+
// inside shared clause of task construct.
3+
4+
// REQUIRES: x86_64-linux
5+
6+
// RUN: %clang_cc1 -debug-info-kind=constructor -DSHARED -x c -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
7+
// RUN: %clang_cc1 -debug-info-kind=constructor -x c -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm %s -o - | FileCheck %s --check-prefix=NEG
8+
// expected-no-diagnostics
9+
10+
// CHECK-LABEL: define internal i32 @.omp_task_entry.
11+
12+
// CHECK-DAG: [[CONTEXT:%[0-9]+]] = load %struct.anon*, %struct.anon** %__context.addr.i, align 8
13+
// CHECK-DAG: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata [[SHARE2:![0-9]+]], metadata !DIExpression(DW_OP_deref))
14+
// CHECK-DAG: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata [[SHARE3:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref))
15+
// CHECK-DAG: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata [[SHARE1:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_deref))
16+
17+
// CHECK-DAG: [[SHARE2]] = !DILocalVariable(name: "share2"
18+
// CHECK-DAG: [[SHARE3]] = !DILocalVariable(name: "share3"
19+
// CHECK-DAG: [[SHARE1]] = !DILocalVariable(name: "share1"
20+
21+
// NEG-LABEL: define internal i32 @.omp_task_entry.
22+
// NEG: [[CONTEXT:%[0-9]+]] = load %struct.anon*, %struct.anon** %__context.addr.i, align 8
23+
// NEG-NOT: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata {{![0-9]+}}, metadata !DIExpression(DW_OP_deref))
24+
25+
extern int printf(const char *, ...);
26+
27+
int foo(int n) {
28+
int share1 = 9, share2 = 11, share3 = 13, priv1, priv2, fpriv;
29+
fpriv = n + 4;
30+
31+
if (n < 2)
32+
return n;
33+
else {
34+
#if SHARED
35+
#pragma omp task shared(share1, share2) private(priv1, priv2) firstprivate(fpriv) shared(share3)
36+
#else
37+
#pragma omp task private(priv1, priv2) firstprivate(fpriv)
38+
#endif
39+
{
40+
priv1 = n;
41+
priv2 = n + 2;
42+
share2 += share3;
43+
printf("share1 = %d, share2 = %d, share3 = %d\n", share1, share2, share3);
44+
share1 = priv1 + priv2 + fpriv + foo(n - 1) + share2 + share3;
45+
}
46+
#pragma omp taskwait
47+
return share1 + share2 + share3;
48+
}
49+
}
50+
51+
int main() {
52+
int n = 10;
53+
printf("foo(%d) = %d\n", n, foo(n));
54+
return 0;
55+
}

0 commit comments

Comments
 (0)