-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[OpenMPIRBuilder] Don't drop debug info for target region. #80692
Conversation
@llvm/pr-subscribers-mlir-llvm @llvm/pr-subscribers-flang-openmp Author: None (abidh) ChangesWhen an outlined function is generated for omp target region, a corresponding DISubprogram was not being generated. This resulted in all the debug information for the target region being dropped. This commit adds DISubprogram for the outlined function if there is one available for the parent function. It also updates the current debug location so that the right scope is used for the entries in the outlined function. With this change in place, I can set source line breakpoint in target region and run to them in debugger. Full diff: https://github.com/llvm/llvm-project/pull/80692.diff 3 Files Affected:
diff --git a/flang/test/Lower/OpenMP/target-debug.f90 b/flang/test/Lower/OpenMP/target-debug.f90
new file mode 100644
index 0000000000000..c9843eba391d7
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-debug.f90
@@ -0,0 +1,18 @@
+!RUN: %flang_fc1 -triple amdgcn-amd-amdhsa %s -debug-info-kind=line-tables-only -fopenmp -fopenmp-is-target-device -emit-llvm -o - | FileCheck %s
+program test
+implicit none
+
+ integer(kind = 4) :: a, b, c, d
+
+ !$omp target map(tofrom: a, b, c, d)
+ a = a + 1
+ ! CHECK: !DILocation(line: [[@LINE-1]]
+ b = a + 2
+ ! CHECK: !DILocation(line: [[@LINE-1]]
+ c = a + 3
+ ! CHECK: !DILocation(line: [[@LINE-1]]
+ d = a + 4
+ ! CHECK: !DILocation(line: [[@LINE-1]]
+ !$omp end target
+
+end program test
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 02b333e9ccd56..f0f26c5b8d8b7 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
@@ -5025,10 +5026,41 @@ static Function *createOutlinedFunction(
ParameterTypes.push_back(Arg->getType());
}
+ auto BB = Builder.GetInsertBlock();
+ auto M = BB->getModule();
auto FuncType = FunctionType::get(Builder.getVoidTy(), ParameterTypes,
/*isVarArg*/ false);
- auto Func = Function::Create(FuncType, GlobalValue::InternalLinkage, FuncName,
- Builder.GetInsertBlock()->getModule());
+ auto Func =
+ Function::Create(FuncType, GlobalValue::InternalLinkage, FuncName, M);
+
+ // If there's a DISubprogram associated with current function, then
+ // generate one for the outlined function.
+ if (Function *parentFunc = BB->getParent()) {
+ if (DISubprogram *SP = parentFunc->getSubprogram()) {
+ DICompileUnit *CU = SP->getUnit();
+ DIBuilder DB(*M, true, CU);
+ DebugLoc DL = Builder.getCurrentDebugLocation();
+ // TODO: We are using nullopt for arguments at the moment. This will need
+ // to be updated when debug data is being generated for variables.
+ DISubroutineType *Ty =
+ DB.createSubroutineType(DB.getOrCreateTypeArray(std::nullopt));
+ DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagDefinition |
+ DISubprogram::SPFlagOptimized |
+ DISubprogram::SPFlagLocalToUnit;
+
+ DISubprogram *OutlinedSP = DB.createFunction(
+ CU, FuncName, FuncName, SP->getFile(), DL.getLine(), Ty, DL.getLine(),
+ DINode::DIFlags::FlagArtificial, SPFlags);
+
+ // Attach subprogram to the function.
+ Func->setSubprogram(OutlinedSP);
+ // Update the CurrentDebugLocation in the builder so that right scope
+ // is used for things inside outlined function.
+ Builder.SetCurrentDebugLocation(
+ DILocation::get(Func->getContext(), DL.getLine(), DL.getCol(),
+ OutlinedSP, DL.getInlinedAt()));
+ }
+ }
// Save insert point.
auto OldInsertPoint = Builder.saveIP();
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index e79d0bb2f65ae..c5b5d12840c4d 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -5827,6 +5827,10 @@ TEST_F(OpenMPIRBuilderTest, TargetRegion) {
BasicBlock *FallbackBlock = Branch->getSuccessor(0);
Iter = FallbackBlock->rbegin();
CallInst *FCall = dyn_cast<CallInst>(&*(++Iter));
+ // 'F' has a dummy DISubprogram which causes OutlinedFunc to also
+ // have a DISubprogram. In this case, the call to OutlinedFunc needs
+ // to have a debug loc, otherwise verifier will complain.
+ FCall->setDebugLoc(DL);
EXPECT_NE(FCall, nullptr);
// Check that the correct aguments are passed in
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to generate MLIR file and
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to generate MLIR file and add test for LLVM IR here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
// If there's a DISubprogram associated with current function, then | ||
// generate one for the outlined function. | ||
if (Function *parentFunc = BB->getParent()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect this to be an unconnected BB at any point?
Here, and below, please use LLVM style. This is not MLIR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think BB will be unconnected. But even if that was to happen, the worst we will do is to drop debug bits as we are already doing.
Thanks for pointing out the style bit. Corrected now.
Ping. Any further review comments for this PR? |
Ping. |
@jdoerfert @DominikAdamski @kiranchandramohan Kindly requesting to review this PR, so that it can land. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG.
module attributes {omp.is_target_device = true} { | ||
llvm.func @_QQmain() { | ||
%0 = llvm.mlir.constant(1 : i64) : i64 | ||
%1 = llvm.alloca %0 x i32 : (i64) -> !llvm.ptr<5> | ||
%2 = llvm.addrspacecast %1 : !llvm.ptr<5> to !llvm.ptr | ||
%3 = llvm.mlir.constant(1 : i64) : i64 | ||
%4 = llvm.alloca %3 x i32 : (i64) -> !llvm.ptr<5> | ||
%5 = llvm.addrspacecast %4 : !llvm.ptr<5> to !llvm.ptr | ||
%6 = llvm.mlir.constant(1 : i64) : i64 | ||
%7 = llvm.alloca %6 x i32 : (i64) -> !llvm.ptr<5> | ||
%8 = llvm.addrspacecast %7 : !llvm.ptr<5> to !llvm.ptr | ||
%9 = omp.map_info var_ptr(%2 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} | ||
%10 = omp.map_info var_ptr(%5 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} | ||
omp.target map_entries(%9 -> %arg0, %10 -> %arg1 : !llvm.ptr, !llvm.ptr) { | ||
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr): | ||
%12 = llvm.mlir.constant(2 : i32) : i32 | ||
%13 = llvm.mlir.constant(1 : i32) : i32 | ||
%14 = llvm.load %arg0 : !llvm.ptr -> i32 loc(#loc2) | ||
%15 = llvm.add %14, %13 : i32 loc(#loc2) | ||
llvm.store %15, %arg0 : i32, !llvm.ptr loc(#loc2) | ||
%16 = llvm.load %arg0 : !llvm.ptr -> i32 loc(#loc3) | ||
%17 = llvm.add %16, %12 : i32 loc(#loc3) | ||
llvm.store %17, %arg1 : i32, !llvm.ptr loc(#loc3) | ||
omp.terminator | ||
} | ||
%11 = omp.map_info var_ptr(%8 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} | ||
omp.target map_entries(%11 -> %arg0 : !llvm.ptr) { | ||
^bb0(%arg0: !llvm.ptr): | ||
%12 = llvm.mlir.constant(1 : i32) : i32 | ||
omp.parallel { | ||
%13 = llvm.load %arg0 : !llvm.ptr -> i32 loc(#loc4) | ||
%14 = llvm.add %13, %12 : i32 loc(#loc4) | ||
llvm.store %14, %arg0 : i32, !llvm.ptr loc(#loc4) | ||
omp.terminator | ||
} | ||
omp.terminator | ||
} | ||
llvm.return | ||
} loc(#loc5) | ||
} loc(#loc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can you minimize this testcase to be as small as possible? We do not need a large region particularly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have minimized the test. I also had to make one other small change after I rebased. There was debug info for variables that gets passed into the targer region. They can fail LLVM verifier checks as the scope of the variable may not match the function created for target region. This may require extra work so I have disabled the debug info for such variables.
✅ With the latest revision this PR passed the C/C++ code formatter. |
24cbf9e
to
a780f18
Compare
I have improved the patch a bit more and added some more tests especially to check that variable in target region don't cause a problem. I have tested it further and it seems ready to merge. Please let me know if there are any further comments. |
@jeanPerier Can you kindly look at the this PR especially the flang changes where I try to skip the debug info generation for variables which will be in OpenMP target region. Is this the right way to do it? I thought about processing DeclOp just in the function entry block which will have the same effect but this seems to make the intention more explicit. |
// FIXME: We currently dont handle variables that are not in the entry | ||
// blocks of the fuctions. These may be variable or arguments used in the | ||
// OpenMP target regions. | ||
if (&funcOp.front() == declOp->getBlock()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can also be variables from Fortran BLOCK constructs, or the selectors from ASSOCIATE/SELECT TYPE/SELECT RANK/SELECT CASE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is fine to do it the way you are doing given we will want to lift this restriction, so any compiler performance gain would be temporary and artificial (it would otherwise be more efficient to walk only the front block).
When an outlined function is generated for omp target region, a corresponding DISubprogram was not being generated. This resulted in all the debug information for the target region being dropped. This commit adds DISubprogram for the outlined function if there is one available for the parent function. It also updates the current debug location so that the right scope is used for the entries in the outlined function. With this change in place, I can set source line breakpoint in target region and run to them in debugger.
The original f90 ->llvmir test has been removed. I have added an MLIR -> llvmir test as per review comments.
These variables currently fail the llvm verifier tests as the scope inside the variable is still point to the parent function of the target region.
It has the extra benefit of saving/restoring the debug location which otherwise could be lost.
When an outlined function is generated for omp target region, a corresponding DISubprogram was not being generated. This resulted in all the debug information for the target region being dropped.
This commit adds DISubprogram for the outlined function if there is one available for the parent function. It also updates the current debug location so that the right scope is used for the entries in the outlined function.
With this change in place, I can set source line breakpoint in target region and run to them in debugger.