[llvm] d56c06e - [flang][debug] Generate DISubprogramAttr for omp::TargetOp. (#146532)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 3 02:38:32 PDT 2025
Author: Abid Qadeer
Date: 2025-07-03T10:38:28+01:00
New Revision: d56c06e6c9f0cf03d75fd755c099a6844ecf38e6
URL: https://github.com/llvm/llvm-project/commit/d56c06e6c9f0cf03d75fd755c099a6844ecf38e6
DIFF: https://github.com/llvm/llvm-project/commit/d56c06e6c9f0cf03d75fd755c099a6844ecf38e6.diff
LOG: [flang][debug] Generate DISubprogramAttr for omp::TargetOp. (#146532)
This is combination of https://github.com/llvm/llvm-project/pull/138149
and https://github.com/llvm/llvm-project/pull/138039 which were opened
separately for ease of reviewing. Only other change is adjustments in 2
tests which have gone in since.
There are `DeclareOp` present for the variables mapped into target
region. That allow us to generate debug information for them. But the
`TargetOp` is still part of parent function and those variables get the
parent function's `DISubprogram` as a scope.
In `OMPIRBuilder`, a new function is created for the `TargetOp`. We also
create a new `DISubprogram` for it. All the variables that were in the
target region now have to be updated to have the correct scope. This
after the fact updating of
debug information becomes very difficult in certain cases. Take the
example of variable arrays. The type of those arrays depend on the
artificial `DILocalVariable`(s) which hold the size(s) of the array.
This new function will now require that we generate the new variable and
and new types. Similar issue exist for character type variables too.
To avoid this after the fact updating, this PR generates a
`DISubprogramAttr` for the `TargetOp` while generating the debug info in
`flang`. Then we don't need to generate a `DISubprogram` in
`OMPIRBuilder`. This change is made a bit more complicated by the the
fact that in new scheme, the debug location already points to the new
`DISubprogram` by the time it reaches `convertOmpTarget`. But we need
some code generation in the parent function so we have to carefully
manage the debug locations.
This fixes issue `#134991`.
Added:
flang/test/Transforms/debug-omp-target-op-1.fir
flang/test/Transforms/debug-omp-target-op-2.fir
mlir/test/Target/LLVMIR/omptarget-debug-empty.mlir
Modified:
flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
mlir/test/Target/LLVMIR/omptarget-debug-loop-loc.mlir
mlir/test/Target/LLVMIR/omptarget-debug-map-link-loc.mlir
mlir/test/Target/LLVMIR/omptarget-debug-nowait.mlir
mlir/test/Target/LLVMIR/omptarget-debug-var-1.mlir
mlir/test/Target/LLVMIR/omptarget-debug-var-2.mlir
mlir/test/Target/LLVMIR/omptarget-debug.mlir
mlir/test/Target/LLVMIR/omptarget-debug2.mlir
mlir/test/Target/LLVMIR/omptarget-parallel-llvm-debug.mlir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 8fa2f38818c02..6eb914e67fd54 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -35,6 +35,7 @@
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -104,6 +105,37 @@ bool debugInfoIsAlreadySet(mlir::Location loc) {
return false;
}
+// Generates the name for the artificial DISubprogram that we are going to
+// generate for omp::TargetOp. Its logic is borrowed from
+// getTargetEntryUniqueInfo and
+// TargetRegionEntryInfo::getTargetRegionEntryFnName to generate the same name.
+// But even if there was a slight mismatch, it is not a problem because this
+// name is artificial and not important to debug experience.
+mlir::StringAttr getTargetFunctionName(mlir::MLIRContext *context,
+ mlir::Location Loc,
+ llvm::StringRef parentName) {
+ auto fileLoc = Loc->findInstanceOf<mlir::FileLineColLoc>();
+
+ assert(fileLoc && "No file found from location");
+ llvm::StringRef fileName = fileLoc.getFilename().getValue();
+
+ llvm::sys::fs::UniqueID id;
+ uint64_t line = fileLoc.getLine();
+ size_t fileId;
+ size_t deviceId;
+ if (auto ec = llvm::sys::fs::getUniqueID(fileName, id)) {
+ fileId = llvm::hash_value(fileName.str());
+ deviceId = 0xdeadf17e;
+ } else {
+ fileId = id.getFile();
+ deviceId = id.getDevice();
+ }
+ return mlir::StringAttr::get(
+ context,
+ std::string(llvm::formatv("__omp_offloading_{0:x-}_{1:x-}_{2}_l{3}",
+ deviceId, fileId, parentName, line)));
+}
+
} // namespace
bool AddDebugInfoPass::createCommonBlockGlobal(
@@ -446,6 +478,79 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
line - 1, false);
}
+ auto addTargetOpDISP = [&](bool lineTableOnly,
+ llvm::ArrayRef<mlir::LLVM::DINodeAttr> entities) {
+ // When we process the DeclareOp inside the OpenMP target region, all the
+ // variables get the DISubprogram of the parent function of the target op as
+ // the scope. In the codegen (to llvm ir), OpenMP target op results in the
+ // creation of a separate function. As the variables in the debug info have
+ // the DISubprogram of the parent function as the scope, the variables
+ // need to be updated at codegen time to avoid verification failures.
+
+ // This updating after the fact becomes more and more
diff icult when types
+ // are dependent on local variables like in the case of variable size arrays
+ // or string. We not only have to generate new variables but also new types.
+ // We can avoid this problem by generating a DISubprogramAttr here for the
+ // target op and make sure that all the variables inside the target region
+ // get the correct scope in the first place.
+ funcOp.walk([&](mlir::omp::TargetOp targetOp) {
+ unsigned line = getLineFromLoc(targetOp.getLoc());
+ mlir::StringAttr name =
+ getTargetFunctionName(context, targetOp.getLoc(), funcOp.getName());
+ mlir::LLVM::DISubprogramFlags flags =
+ mlir::LLVM::DISubprogramFlags::Definition |
+ mlir::LLVM::DISubprogramFlags::LocalToUnit;
+ if (isOptimized)
+ flags = flags | mlir::LLVM::DISubprogramFlags::Optimized;
+
+ mlir::DistinctAttr id =
+ mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
+ llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
+ types.push_back(mlir::LLVM::DINullTypeAttr::get(context));
+ for (auto arg : targetOp.getRegion().getArguments()) {
+ auto tyAttr = typeGen.convertType(fir::unwrapRefType(arg.getType()),
+ fileAttr, cuAttr, /*declOp=*/nullptr);
+ types.push_back(tyAttr);
+ }
+ CC = llvm::dwarf::getCallingConvention("DW_CC_normal");
+ mlir::LLVM::DISubroutineTypeAttr spTy =
+ mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
+ if (lineTableOnly) {
+ auto spAttr = mlir::LLVM::DISubprogramAttr::get(
+ context, id, compilationUnit, Scope, name, name, funcFileAttr, line,
+ line, flags, spTy, /*retainedNodes=*/{}, /*annotations=*/{});
+ targetOp->setLoc(builder.getFusedLoc({targetOp.getLoc()}, spAttr));
+ return;
+ }
+ mlir::DistinctAttr recId =
+ mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
+ auto spAttr = mlir::LLVM::DISubprogramAttr::get(
+ context, recId, /*isRecSelf=*/true, id, compilationUnit, Scope, name,
+ name, funcFileAttr, line, line, flags, spTy, /*retainedNodes=*/{},
+ /*annotations=*/{});
+
+ // Make sure that information about the imported modules is copied in the
+ // new function.
+ llvm::SmallVector<mlir::LLVM::DINodeAttr> opEntities;
+ for (mlir::LLVM::DINodeAttr N : entities) {
+ if (auto entity = mlir::dyn_cast<mlir::LLVM::DIImportedEntityAttr>(N)) {
+ auto importedEntity = mlir::LLVM::DIImportedEntityAttr::get(
+ context, llvm::dwarf::DW_TAG_imported_module, spAttr,
+ entity.getEntity(), fileAttr, /*line=*/1, /*name=*/nullptr,
+ /*elements*/ {});
+ opEntities.push_back(importedEntity);
+ }
+ }
+
+ id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
+ spAttr = mlir::LLVM::DISubprogramAttr::get(
+ context, recId, /*isRecSelf=*/false, id, compilationUnit, Scope, name,
+ name, funcFileAttr, line, line, flags, spTy, opEntities,
+ /*annotations=*/{});
+ targetOp->setLoc(builder.getFusedLoc({targetOp.getLoc()}, spAttr));
+ });
+ };
+
// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly) {
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
@@ -453,6 +558,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{},
/*annotations=*/{});
funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
+ addTargetOpDISP(/*lineTableOnly=*/true, /*entities=*/{});
return;
}
@@ -510,9 +616,18 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
funcName, fullName, funcFileAttr, line, line, subprogramFlags,
subTypeAttr, entities, /*annotations=*/{});
funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
+ addTargetOpDISP(/*lineTableOnly=*/false, entities);
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
- handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable);
+ mlir::LLVM::DISubprogramAttr spTy = spAttr;
+ if (auto tOp = declOp->getParentOfType<mlir::omp::TargetOp>()) {
+ if (auto fusedLoc = llvm::dyn_cast<mlir::FusedLoc>(tOp.getLoc())) {
+ if (auto sp = llvm::dyn_cast<mlir::LLVM::DISubprogramAttr>(
+ fusedLoc.getMetadata()))
+ spTy = sp;
+ }
+ }
+ handleDeclareOp(declOp, fileAttr, spTy, typeGen, symbolTable);
});
// commonBlockMap ensures that we don't create multiple DICommonBlockAttr of
// the same name in one function. But it is ok (rather required) to create
diff --git a/flang/test/Transforms/debug-omp-target-op-1.fir b/flang/test/Transforms/debug-omp-target-op-1.fir
new file mode 100644
index 0000000000000..6b895b732c42b
--- /dev/null
+++ b/flang/test/Transforms/debug-omp-target-op-1.fir
@@ -0,0 +1,40 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+// RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=LINETABLE
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
+ func.func @_QQmain() attributes {fir.bindc_name = "test"} {
+ %c13_i32 = arith.constant 13 : i32
+ %c12_i32 = arith.constant 12 : i32
+ %c6_i32 = arith.constant 6 : i32
+ %c1_i32 = arith.constant 1 : i32
+ %c5_i32 = arith.constant 5 : i32
+ %0 = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"} loc(#loc1)
+ %1 = fircg.ext_declare %0 {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc1)
+ %2 = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"} loc(#loc2)
+ %3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc2)
+ %4 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "x"}
+ %5 = omp.map.info var_ptr(%3 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "y"}
+ omp.target map_entries(%4 -> %arg0, %5 -> %arg1 : !fir.ref<i32>, !fir.ref<i32>) {
+ %16 = fircg.ext_declare %arg0 {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc3)
+ %17 = fircg.ext_declare %arg1 {uniq_name = "_QFEy"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc4)
+ omp.terminator
+ } loc(#loc5)
+ return
+ }
+}
+#loc1 = loc("test.f90":1:1)
+#loc2 = loc("test.f90":3:1)
+#loc3 = loc("test.f90":7:1)
+#loc4 = loc("test.f90":8:1)
+#loc5 = loc("test.f90":6:1)
+
+// CHECK: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "test"{{.*}}>
+// CHECK: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_QQmain_l6"{{.*}}line = 6{{.*}}subprogramFlags = "LocalToUnit|Definition"{{.*}}>
+// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "x"{{.*}}line = 1, type = #[[TY:.*]]>
+// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "y"{{.*}}line = 3, type = #[[TY]]>
+// CHECK: #llvm.di_local_variable<scope = #[[SP1]], name = "x"{{.*}}line = 7, type = #[[TY]]>
+// CHECK: #llvm.di_local_variable<scope = #[[SP1]], name = "y"{{.*}}line = 8, type = #[[TY]]>
+
+// LINETABLE: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "test"{{.*}}>
+// LINETABLE: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_QQmain_l6"{{.*}}line = 6{{.*}}subprogramFlags = "LocalToUnit|Definition"{{.*}}>
+// LINETABLE-NOT: #llvm.di_local_variable
diff --git a/flang/test/Transforms/debug-omp-target-op-2.fir b/flang/test/Transforms/debug-omp-target-op-2.fir
new file mode 100644
index 0000000000000..15dcf2389b21d
--- /dev/null
+++ b/flang/test/Transforms/debug-omp-target-op-2.fir
@@ -0,0 +1,53 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
+ func.func @fn_(%arg0: !fir.ref<!fir.array<?x?xi32>> {fir.bindc_name = "b"}, %arg1: !fir.ref<i32> {fir.bindc_name = "c"}, %arg2: !fir.ref<i32> {fir.bindc_name = "d"}) {
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.alloca i32
+ %1 = fir.alloca i32
+ %2 = fir.undefined !fir.dscope
+ %3 = fircg.ext_declare %arg1 dummy_scope %2 {uniq_name = "_QFfnEc"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc2)
+ %4 = fircg.ext_declare %arg2 dummy_scope %2 {uniq_name = "_QFfnEd"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %5 = fir.load %3 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %9 = fir.load %4 : !fir.ref<i32>
+ %10 = fir.convert %9 : (i32) -> index
+ %15 = fircg.ext_declare %arg0(%6, %10) dummy_scope %2 {uniq_name = "_QFfnEb"} : (!fir.ref<!fir.array<?x?xi32>>, index, index, !fir.dscope) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc4)
+ %16 = fircg.ext_embox %15(%6, %10) : (!fir.ref<!fir.array<?x?xi32>>, index, index) -> !fir.box<!fir.array<?x?xi32>>
+ %17:3 = fir.box_dims %16, %c0 : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index)
+ %18 = arith.subi %17#1, %c1 : index
+ %19 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%18 : index) extent(%17#1 : index) stride(%17#2 : index) start_idx(%c1 : index) {stride_in_bytes = true}
+ %20 = arith.muli %17#2, %17#1 : index
+ %21:3 = fir.box_dims %16, %c1 : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index)
+ %22 = arith.subi %21#1, %c1 : index
+ %23 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%22 : index) extent(%21#1 : index) stride(%20 : index) start_idx(%c1 : index) {stride_in_bytes = true}
+ %24 = omp.map.info var_ptr(%15 : !fir.ref<!fir.array<?x?xi32>>, i32) map_clauses(tofrom) capture(ByRef) bounds(%19, %23) -> !fir.ref<!fir.array<?x?xi32>> {name = "b"}
+ %25 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = ""}
+ %26 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = ""}
+ omp.target map_entries(%24 -> %arg3, %25 -> %arg4, %26 -> %arg5 : !fir.ref<!fir.array<?x?xi32>>, !fir.ref<i32>, !fir.ref<i32>) {
+ %27 = fir.load %arg5 : !fir.ref<i32>
+ %28 = fir.load %arg4 : !fir.ref<i32>
+ %29 = fir.convert %27 : (i32) -> index
+ %31 = fir.convert %28 : (i32) -> index
+ %37 = fircg.ext_declare %arg3(%29, %31) {uniq_name = "_QFfnEb"} : (!fir.ref<!fir.array<?x?xi32>>, index, index) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc5)
+ omp.terminator
+ } loc(#loc6)
+ return
+ } loc(#loc7)
+}
+#loc1 = loc("test.f90":1:1)
+#loc2 = loc("test.f90":3:1)
+#loc3 = loc("test.f90":7:1)
+#loc4 = loc("test.f90":8:1)
+#loc5 = loc("test.f90":6:1)
+#loc6 = loc("test.f90":16:1)
+#loc7 = loc("test.f90":26:1)
+
+
+// Test that variable size arrays inside target regions get their own
+// compiler generated variables for size.
+
+// CHECK: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_fn__l16"{{.*}}>
+// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "._QFfnEb1"{{.*}}>
+// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "._QFfnEb2"{{.*}}>
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 85451b1233f96..db792a3b52d24 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -6891,23 +6891,19 @@ static void FixupDebugInfoForOutlinedFunction(
if (!NewSP)
return;
- DenseMap<const MDNode *, MDNode *> Cache;
SmallDenseMap<DILocalVariable *, DILocalVariable *> RemappedVariables;
auto GetUpdatedDIVariable = [&](DILocalVariable *OldVar, unsigned arg) {
- auto NewSP = Func->getSubprogram();
DILocalVariable *&NewVar = RemappedVariables[OldVar];
// Only use cached variable if the arg number matches. This is important
// so that DIVariable created for privatized variables are not discarded.
if (NewVar && (arg == NewVar->getArg()))
return NewVar;
- DILocalScope *NewScope = DILocalScope::cloneScopeForSubprogram(
- *OldVar->getScope(), *NewSP, Builder.getContext(), Cache);
NewVar = llvm::DILocalVariable::get(
- Builder.getContext(), NewScope, OldVar->getName(), OldVar->getFile(),
- OldVar->getLine(), OldVar->getType(), arg, OldVar->getFlags(),
- OldVar->getAlignInBits(), OldVar->getAnnotations());
+ Builder.getContext(), OldVar->getScope(), OldVar->getName(),
+ OldVar->getFile(), OldVar->getLine(), OldVar->getType(), arg,
+ OldVar->getFlags(), OldVar->getAlignInBits(), OldVar->getAnnotations());
return NewVar;
};
@@ -6921,7 +6917,8 @@ static void FixupDebugInfoForOutlinedFunction(
ArgNo = std::get<1>(Iter->second) + 1;
}
}
- DR->setVariable(GetUpdatedDIVariable(OldVar, ArgNo));
+ if (ArgNo != 0)
+ DR->setVariable(GetUpdatedDIVariable(OldVar, ArgNo));
};
// The location and scope of variable intrinsics and records still point to
@@ -7000,36 +6997,9 @@ static Expected<Function *> createOutlinedFunction(
// Save insert point.
IRBuilder<>::InsertPointGuard IPG(Builder);
- // 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();
- if (DL) {
- // 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({}));
- 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()));
- }
- }
- }
+ // We will generate the entries in the outlined function but the debug
+ // location may still be pointing to the parent function. Reset it now.
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
// Generate the region into the function.
BasicBlock *EntryBB = BasicBlock::Create(Builder.getContext(), "entry", Func);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 7b07243c5f843..883d179580e0c 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -5395,9 +5395,27 @@ static LogicalResult
convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
auto targetOp = cast<omp::TargetOp>(opInst);
+ // The current debug location already has the DISubprogram for the outlined
+ // function that will be created for the target op. We save it here so that
+ // we can set it on the outlined function.
+ llvm::DebugLoc outlinedFnLoc = builder.getCurrentDebugLocation();
if (failed(checkImplementationStatus(opInst)))
return failure();
+ // During the handling of target op, we will generate instructions in the
+ // parent function like call to the oulined function or branch to a new
+ // BasicBlock. We set the debug location here to parent function so that those
+ // get the correct debug locations. For outlined functions, the normal MLIR op
+ // conversion will automatically pick the correct location.
+ llvm::BasicBlock *parentBB = builder.GetInsertBlock();
+ assert(parentBB && "No insert block is set for the builder");
+ llvm::Function *parentLLVMFn = parentBB->getParent();
+ assert(parentLLVMFn && "Parent Function must be valid");
+ if (llvm::DISubprogram *SP = parentLLVMFn->getSubprogram())
+ builder.SetCurrentDebugLocation(llvm::DILocation::get(
+ parentLLVMFn->getContext(), outlinedFnLoc.getLine(),
+ outlinedFnLoc.getCol(), SP, outlinedFnLoc.getInlinedAt()));
+
llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
bool isTargetDevice = ompBuilder->Config.isTargetDevice();
bool isGPU = ompBuilder->Config.isGPU();
@@ -5491,6 +5509,9 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
assert(llvmParentFn && llvmOutlinedFn &&
"Both parent and outlined functions must exist at this point");
+ if (outlinedFnLoc && llvmParentFn->getSubprogram())
+ llvmOutlinedFn->setSubprogram(outlinedFnLoc->getScope()->getSubprogram());
+
if (auto attr = llvmParentFn->getFnAttribute("target-cpu");
attr.isStringAttribute())
llvmOutlinedFn->addFnAttr(attr);
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-empty.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-empty.mlir
new file mode 100644
index 0000000000000..45e5d2612e2c2
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-empty.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+module attributes {omp.is_target_device = false} {
+ llvm.func @test() {
+ omp.target {
+ omp.terminator
+ } loc(#loc4)
+ llvm.return
+ } loc(#loc3)
+}
+#file = #llvm.di_file<"target.f90" in "">
+#cu = #llvm.di_compile_unit<id = distinct[0]<>,
+ sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false,
+ emissionKind = Full>
+#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
+#sp = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #cu, scope = #file,
+ name = "_QQmain", file = #file, subprogramFlags = "Definition", type = #sp_ty>
+#sp1 = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file,
+ name = "__omp_offloading_target", file = #file, subprogramFlags = "Definition",
+ type = #sp_ty>
+#loc1 = loc("target.f90":1:1)
+#loc2 = loc("target.f90":46:3)
+#loc3 = loc(fused<#sp>[#loc1])
+#loc4 = loc(fused<#sp1>[#loc2])
+
+// CHECK: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_target"{{.*}})
+
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-loop-loc.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-loop-loc.mlir
index a755cef98d7c4..c3320382f8d45 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug-loop-loc.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-loop-loc.mlir
@@ -41,7 +41,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
omp.terminator loc(#loc9)
} loc(#loc9)
omp.terminator loc(#loc9)
- } loc(#loc9)
+ } loc(#loc15)
llvm.return loc(#loc9)
} loc(#loc14)
llvm.mlir.global internal @_QFEarray() {addr_space = 0 : i32} : !llvm.array<16384 x i32> {
@@ -59,7 +59,9 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
#di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang", isOptimized = true, emissionKind = LineTablesOnly>
#di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program, types = #di_null_type>
#di_subprogram = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "main", file = #di_file, subprogramFlags = "Definition|Optimized|MainSubprogram", type = #di_subroutine_type>
+#di_subprogram1 = #llvm.di_subprogram<compileUnit = #di_compile_unit, name = "target", file = #di_file, subprogramFlags = "Definition", type = #di_subroutine_type>
#loc14 = loc(fused<#di_subprogram>[#loc3])
+#loc15 = loc(fused<#di_subprogram1>[#loc9])
// CHECK: call void @__kmpc_distribute_static{{.*}}!dbg
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-map-link-loc.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-map-link-loc.mlir
index 4495e1559a889..492610251769c 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug-map-link-loc.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-map-link-loc.mlir
@@ -16,7 +16,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
%16 = llvm.load %arg1 : !llvm.ptr -> i32 loc(#loc5)
llvm.store %16, %arg0 : i32, !llvm.ptr loc(#loc5)
omp.terminator loc(#loc5)
- } loc(#loc5)
+ } loc(#loc16)
llvm.return loc(#loc6)
} loc(#loc15)
}
@@ -31,9 +31,13 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
compileUnit = #di_compile_unit, scope = #di_file, name = "main",
file = #di_file, subprogramFlags = "Definition|MainSubprogram",
type = #di_subroutine_type>
+#di_subprogram1 = #llvm.di_subprogram<compileUnit = #di_compile_unit,
+ name = "target", file = #di_file, subprogramFlags = "Definition",
+ type = #di_subroutine_type>
#loc1 = loc("test.f90":3:18)
#loc2 = loc("test.f90":7:7)
#loc3 = loc("test.f90":9:18)
#loc5 = loc("test.f90":11:7)
#loc6 = loc("test.f90":12:7)
#loc15 = loc(fused<#di_subprogram>[#loc2])
+#loc16 = loc(fused<#di_subprogram1>[#loc5])
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-nowait.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-nowait.mlir
index eaa88d9dd6053..3bd724f42e8ce 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug-nowait.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-nowait.mlir
@@ -20,7 +20,7 @@ module attributes {omp.is_target_device = false} {
^bb3: // pred: ^bb1
llvm.store %13, %arg1 : i32, !llvm.ptr
omp.terminator
- }
+ } loc(#loc3)
llvm.return
} loc(#loc2)
}
@@ -34,7 +34,10 @@ module attributes {omp.is_target_device = false} {
types = #di_null_type>
#sp = #llvm.di_subprogram<compileUnit = #cu, name = "main", file=#file,
subprogramFlags = "Definition", type = #sp_ty>
+#sp1 = #llvm.di_subprogram<compileUnit = #cu, name = "target", file=#file,
+ subprogramFlags = "Definition", type = #sp_ty>
#loc1 = loc("test.f90":6:7)
#loc2 = loc(fused<#sp>[#loc1])
+#loc3 = loc(fused<#sp1>[#loc1])
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-var-1.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-var-1.mlir
index ea92589bbd031..8f42995af23a8 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug-var-1.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-var-1.mlir
@@ -19,11 +19,13 @@
#g_var_expr = #llvm.di_global_variable_expression<var = #g_var>
#sp = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file,
name = "test", file = #file, subprogramFlags = "Definition", type = #sp_ty>
-#var_arr = #llvm.di_local_variable<scope = #sp,
+#sp1 = #llvm.di_subprogram<id = distinct[3]<>, compileUnit = #cu, scope = #file,
+ name = "target", file = #file, subprogramFlags = "Definition", type = #sp_ty>
+#var_arr = #llvm.di_local_variable<scope = #sp1,
name = "arr", file = #file, line = 4, type = #array_ty>
-#var_i = #llvm.di_local_variable<scope = #sp,
+#var_i = #llvm.di_local_variable<scope = #sp1,
name = "i", file = #file, line = 13, type = #int_ty>
-#var_x = #llvm.di_local_variable<scope = #sp,
+#var_x = #llvm.di_local_variable<scope = #sp1,
name = "x", file = #file, line = 12, type = #real_ty>
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memory_space", 5 : ui32>>, llvm.target_triple = "amdgcn-amd-amdhsa", omp.is_target_device = true} {
@@ -47,7 +49,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
llvm.intr.dbg.declare #var_arr = %arg1 : !llvm.ptr
llvm.intr.dbg.declare #var_i = %arg2 : !llvm.ptr
omp.terminator
- }
+ } loc(#loc5)
llvm.return
} loc(#loc3)
llvm.mlir.global internal @_QFEarr() {addr_space = 0 : i32, dbg_exprs = [#g_var_expr]} : !llvm.array<10 x i32> {
@@ -57,8 +59,9 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
#loc2 = loc("target.f90":11:7)
#loc3 = loc(fused<#sp>[#loc2])
#loc4 = loc(fused<#g_var>[#loc1])
+#loc5 = loc(fused<#sp1>[#loc2])
-// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "__omp_offloading{{.*}}test{{.*}})
+// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "target"{{.*}})
// CHECK: !DILocalVariable(name: "dyn_ptr", arg: 1, scope: ![[SP]]{{.*}}flags: DIFlagArtificial)
// CHECK: !DILocalVariable(name: "x", arg: 2, scope: ![[SP]]{{.*}})
// CHECK: !DILocalVariable(name: "arr", arg: 3, scope: ![[SP]]{{.*}})
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-var-2.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-var-2.mlir
index 22db86fd85e2c..11a07dfd9a180 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug-var-2.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-var-2.mlir
@@ -19,11 +19,13 @@
#g_var_expr = #llvm.di_global_variable_expression<var = #g_var>
#sp = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file,
name = "test", file = #file, subprogramFlags = "Definition", type = #sp_ty>
-#var_arr = #llvm.di_local_variable<scope = #sp,
+#sp1 = #llvm.di_subprogram<id = distinct[3]<>, compileUnit = #cu, scope = #file,
+ name = "target", file = #file, subprogramFlags = "Definition", type = #sp_ty>
+#var_arr = #llvm.di_local_variable<scope = #sp1,
name = "arr", file = #file, line = 4, type = #array_ty>
-#var_i = #llvm.di_local_variable<scope = #sp,
+#var_i = #llvm.di_local_variable<scope = #sp1,
name = "i", file = #file, line = 13, type = #int_ty>
-#var_x = #llvm.di_local_variable<scope = #sp,
+#var_x = #llvm.di_local_variable<scope = #sp1,
name = "x", file = #file, line = 12, type = #real_ty>
module attributes {omp.is_target_device = false} {
@@ -45,7 +47,7 @@ module attributes {omp.is_target_device = false} {
llvm.intr.dbg.declare #var_arr = %arg1 : !llvm.ptr
llvm.intr.dbg.declare #var_i = %arg2 : !llvm.ptr
omp.terminator
- }
+ } loc(#loc5)
llvm.return
} loc(#loc3)
llvm.mlir.global internal @_QFEarr() {addr_space = 0 : i32, dbg_exprs = [#g_var_expr]} : !llvm.array<10 x i32> {
@@ -55,8 +57,9 @@ module attributes {omp.is_target_device = false} {
#loc2 = loc("target.f90":11:7)
#loc3 = loc(fused<#sp>[#loc2])
#loc4 = loc(fused<#g_var>[#loc1])
+#loc5 = loc(fused<#sp1>[#loc2])
-// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "__omp_offloading{{.*}}test{{.*}})
+// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "target"{{.*}})
// CHECK: !DILocalVariable(name: "x", arg: 1, scope: ![[SP]]{{.*}})
// CHECK: !DILocalVariable(name: "arr", arg: 2, scope: ![[SP]]{{.*}})
// CHECK: !DILocalVariable(name: "i", arg: 3, scope: ![[SP]]{{.*}})
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug.mlir b/mlir/test/Target/LLVMIR/omptarget-debug.mlir
index 9c8344d69dc74..ab687f198b9b4 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug.mlir
@@ -10,7 +10,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
%13 = llvm.mlir.constant(1 : i32) : i32
llvm.store %13, %arg0 : i32, !llvm.ptr loc(#loc2)
omp.terminator
- }
+ } loc(#loc4)
llvm.return
} loc(#loc3)
}
@@ -21,9 +21,13 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
#sp = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #cu, scope = #file,
name = "_QQmain", file = #file, subprogramFlags = "Definition", type = #sp_ty>
+#sp1 = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file,
+ name = "__omp_offloading_target", file = #file, subprogramFlags = "Definition",
+ type = #sp_ty>
#loc1 = loc("target.f90":1:1)
#loc2 = loc("target.f90":46:3)
#loc3 = loc(fused<#sp>[#loc1])
+#loc4 = loc(fused<#sp1>[#loc1])
-// CHECK-DAG: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_{{.*}}"{{.*}})
+// CHECK-DAG: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_target"{{.*}})
// CHECK-DAG: !DILocation(line: 46, column: 3, scope: ![[SP]])
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug2.mlir b/mlir/test/Target/LLVMIR/omptarget-debug2.mlir
index 78dc6e18a40a7..6cf75af38f916 100644
--- a/mlir/test/Target/LLVMIR/omptarget-debug2.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-debug2.mlir
@@ -11,7 +11,7 @@ module attributes {omp.is_target_device = false} {
%13 = llvm.mlir.constant(1 : i32) : i32
llvm.store %13, %arg0 : i32, !llvm.ptr loc(#loc2)
omp.terminator
- }
+ } loc(#loc4)
llvm.return
} loc(#loc3)
}
@@ -22,9 +22,13 @@ module attributes {omp.is_target_device = false} {
#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
#sp = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #cu, scope = #file,
name = "_QQmain", file = #file, subprogramFlags = "Definition", type = #sp_ty>
+#sp1 = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file,
+ name = "__omp_offloading_target", file = #file, subprogramFlags = "Definition",
+ type = #sp_ty>
#loc1 = loc("target.f90":1:1)
#loc2 = loc("target.f90":46:3)
#loc3 = loc(fused<#sp>[#loc1])
+#loc4 = loc(fused<#sp1>[#loc1])
-// CHECK-DAG: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_{{.*}}"{{.*}})
+// CHECK-DAG: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_target"{{.*}})
// CHECK-DAG: !DILocation(line: 46, column: 3, scope: ![[SP]])
diff --git a/mlir/test/Target/LLVMIR/omptarget-parallel-llvm-debug.mlir b/mlir/test/Target/LLVMIR/omptarget-parallel-llvm-debug.mlir
index 3c45f1f1c76fb..b18338ea35cc3 100644
--- a/mlir/test/Target/LLVMIR/omptarget-parallel-llvm-debug.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-parallel-llvm-debug.mlir
@@ -6,8 +6,10 @@
#cu = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang", isOptimized = false, emissionKind = Full>
#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_program, types = #di_null_type>
#sp = #llvm.di_subprogram<compileUnit = #cu, scope = #di_file, name = "test", file = #di_file, subprogramFlags = "Definition", type = #sp_ty>
+#sp1 = #llvm.di_subprogram<compileUnit = #cu, scope = #di_file, name = "kernel", file = #di_file, subprogramFlags = "Definition", type = #sp_ty>
#int_ty = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
#var_x = #llvm.di_local_variable<scope = #sp, name = "x", file = #di_file, type = #int_ty>
+#var_x1 = #llvm.di_local_variable<scope = #sp1, name = "x", file = #di_file, type = #int_ty>
module attributes {dlti.dl_spec = #dlti.dl_spec<i32 = dense<32> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, f80 = dense<128> : vector<2xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr = dense<64> : vector<4xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, "dlti.endianness" = "little", "dlti.stack_alignment" = 128 : i64, "dlti.mangling_mode" = "e">, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", fir.target_cpu = "x86-64", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.ident = "flang version 21.0.0 (/home/haqadeer/work/src/aomp-llvm-project/flang 793f9220ab32f92fc3b253efec2e332c18090e53)", llvm.target_triple = "x86_64-unknown-linux-gnu", omp.is_gpu = false, omp.is_target_device = false, omp.requires = #omp<clause_requires none>, omp.target_triples = ["amdgcn-amd-amdhsa"], omp.version = #omp.version<version = 52>} {
llvm.func @_QQmain() attributes {fir.bindc_name = "test", frame_pointer = #llvm.framePointerKind<all>, target_cpu = "x86-64"} {
%0 = llvm.mlir.constant(1 : i64) : i64
@@ -16,7 +18,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i32 = dense<32> : vector<2xi64>,
%5 = omp.map.info var_ptr(%1 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "x"}
omp.target map_entries(%5 -> %arg0 : !llvm.ptr) {
%6 = llvm.mlir.constant(1 : i32) : i32
- llvm.intr.dbg.declare #var_x = %arg0 : !llvm.ptr loc(#loc2)
+ llvm.intr.dbg.declare #var_x1 = %arg0 : !llvm.ptr loc(#loc3)
omp.parallel {
%7 = llvm.load %arg0 : !llvm.ptr -> i32
%8 = llvm.add %7, %6 : i32
@@ -24,12 +26,14 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i32 = dense<32> : vector<2xi64>,
omp.terminator
}
omp.terminator
- }
+ } loc(#loc4)
llvm.return
} loc(#loc10)
}
#loc1 = loc("target.f90":1:7)
#loc2 = loc("target.f90":3:18)
+#loc3 = loc("target.f90":6:18)
+#loc4 = loc(fused<#sp1>[#loc3])
#loc10 = loc(fused<#sp>[#loc1])
More information about the llvm-commits
mailing list