forked from OSchip/llvm-project
[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
This commit is contained in:
parent
a9bb97e841
commit
5eb271880c
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
|
|
@ -459,6 +459,11 @@ public:
|
|||
/// 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue