Skip to content

Commit

Permalink
[clang][OpenMP][DebugInfo] Debug support for variables in shared clau…
Browse files Browse the repository at this point in the history
…se 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
  • Loading branch information
alokkrsharma committed Dec 22, 2021
1 parent a9bb97e commit 5eb2718
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
50 changes: 50 additions & 0 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/AtomicOrdering.h"
using namespace clang;
using namespace CodeGen;
Expand Down Expand Up @@ -4431,6 +4434,53 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
UntiedLocalVars;
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
// Generate debug info for variables present in shared clause.
if (auto *DI = CGF.getDebugInfo()) {
llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields =
CGF.CapturedStmtInfo->getCaptureFields();
llvm::Value *ContextValue = CGF.CapturedStmtInfo->getContextValue();
if (CaptureFields.size() && ContextValue) {
unsigned CharWidth = CGF.getContext().getCharWidth();
// The shared variables are packed together as members of structure.
// So the address of each shared variable can be computed by adding
// offset of it (within record) to the base address of record. For each
// shared variable, debug intrinsic llvm.dbg.declare is generated with
// appropriate expressions (DIExpression).
// Ex:
// %12 = load %struct.anon*, %struct.anon** %__context.addr.i
// call void @llvm.dbg.declare(metadata %struct.anon* %12,
// metadata !svar1,
// metadata !DIExpression(DW_OP_deref))
// call void @llvm.dbg.declare(metadata %struct.anon* %12,
// metadata !svar2,
// metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref))
for (auto It = CaptureFields.begin(); It != CaptureFields.end(); ++It) {
const VarDecl *SharedVar = It->first;
RecordDecl *CaptureRecord = It->second->getParent();
const ASTRecordLayout &Layout =
CGF.getContext().getASTRecordLayout(CaptureRecord);
unsigned Offset =
Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth;
(void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
CGF.Builder, false);
llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back();
// Get the call dbg.declare instruction we just created and update
// its DIExpression to add offset to base address.
if (auto DDI = dyn_cast<llvm::DbgVariableIntrinsic>(&Last)) {
SmallVector<uint64_t, 8> Ops;
// Add offset to the base address if non zero.
if (Offset) {
Ops.push_back(llvm::dwarf::DW_OP_plus_uconst);
Ops.push_back(Offset);
}
Ops.push_back(llvm::dwarf::DW_OP_deref);
auto &Ctx = DDI->getContext();
llvm::DIExpression *DIExpr = llvm::DIExpression::get(Ctx, Ops);
Last.setOperand(2, llvm::MetadataAsValue::get(Ctx, DIExpr));
}
}
}
}
llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> FirstprivatePtrs;
if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
!Data.LastprivateVars.empty() || !Data.PrivateLocals.empty()) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,11 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Get the name of the capture helper.
virtual StringRef getHelperName() const { return "__captured_stmt"; }

/// Get the CaptureFields
llvm::SmallDenseMap<const VarDecl *, FieldDecl *> getCaptureFields() {
return CaptureFields;
}

private:
/// The kind of captured statement being generated.
CapturedRegionKind Kind;
Expand Down
55 changes: 55 additions & 0 deletions clang/test/OpenMP/debug_task_shared.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// This testcase checks emission of debug info for variables
// inside shared clause of task construct.

// REQUIRES: x86_64-linux

// 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
// 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
// expected-no-diagnostics

// CHECK-LABEL: define internal i32 @.omp_task_entry.

// CHECK-DAG: [[CONTEXT:%[0-9]+]] = load %struct.anon*, %struct.anon** %__context.addr.i, align 8
// CHECK-DAG: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata [[SHARE2:![0-9]+]], metadata !DIExpression(DW_OP_deref))
// 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))
// 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))

// CHECK-DAG: [[SHARE2]] = !DILocalVariable(name: "share2"
// CHECK-DAG: [[SHARE3]] = !DILocalVariable(name: "share3"
// CHECK-DAG: [[SHARE1]] = !DILocalVariable(name: "share1"

// NEG-LABEL: define internal i32 @.omp_task_entry.
// NEG: [[CONTEXT:%[0-9]+]] = load %struct.anon*, %struct.anon** %__context.addr.i, align 8
// NEG-NOT: call void @llvm.dbg.declare(metadata %struct.anon* [[CONTEXT]], metadata {{![0-9]+}}, metadata !DIExpression(DW_OP_deref))

extern int printf(const char *, ...);

int foo(int n) {
int share1 = 9, share2 = 11, share3 = 13, priv1, priv2, fpriv;
fpriv = n + 4;

if (n < 2)
return n;
else {
#if SHARED
#pragma omp task shared(share1, share2) private(priv1, priv2) firstprivate(fpriv) shared(share3)
#else
#pragma omp task private(priv1, priv2) firstprivate(fpriv)
#endif
{
priv1 = n;
priv2 = n + 2;
share2 += share3;
printf("share1 = %d, share2 = %d, share3 = %d\n", share1, share2, share3);
share1 = priv1 + priv2 + fpriv + foo(n - 1) + share2 + share3;
}
#pragma omp taskwait
return share1 + share2 + share3;
}
}

int main() {
int n = 10;
printf("foo(%d) = %d\n", n, foo(n));
return 0;
}

0 comments on commit 5eb2718

Please sign in to comment.