[Mlir-commits] [mlir] 877c39a - [OpenMPIRBuilder] Handle empty blocks in restoreIPandDebugLoc (#212535)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Aug 3 08:05:11 PDT 2026


Author: Abid Qadeer
Date: 2026-08-03T16:05:07+01:00
New Revision: 877c39aa8e15abe05c4c9562743d49b29689f2ce

URL: https://github.com/llvm/llvm-project/commit/877c39aa8e15abe05c4c9562743d49b29689f2ce
DIFF: https://github.com/llvm/llvm-project/commit/877c39aa8e15abe05c4c9562743d49b29689f2ce.diff

LOG: [OpenMPIRBuilder] Handle empty blocks in restoreIPandDebugLoc (#212535)

`restoreIPandDebugLoc` previously only recovered a debug location when
the insertion block was non-empty, using its last instruction. For an
empty block it left the current debug location unchanged so instructions
emitted afterwards could have wrong debug location.

This PR enhance `restoreIPandDebugLoc` to also handle the empty-block
case: when the insertion point is at the end of an empty block,
synthesize a location scoped to the parent function's subprogram
provided the function has debug metadata.

This helps us get a valid debug location when we switch to `CodeGenIP`
in `emitOffloadingArrays` even when `CodeGenIP` is pointing to an empty
`BB`.

Fixes https://github.com/llvm/llvm-project/issues/212488

Co-authored-by: Cursor <cursoragent at cursor.com>

Added: 
    mlir/test/Target/LLVMIR/openmp-target-in-reduction-debug.mlir

Modified: 
    llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 9a49f4124da5e..ca191165c61c1 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -162,16 +162,31 @@ static bool isValidWorkshareLoopScheduleType(OMPScheduleType SchedType) {
 }
 #endif
 
-/// This is wrapper over IRBuilderBase::restoreIP that also restores the current
-/// debug location to the last instruction in the specified basic block if the
-/// insert point points to the end of the block.
+/// This is a wrapper over IRBuilderBase::restoreIP that also restores a current
+/// debug location when the insert point is at the end of a block. It picks a
+/// location scoped to the current function: the block's last instruction
+/// location if the block is non-empty, otherwise a location synthesized from
+///  the function's subprogram (when the function has debug info).
 static void restoreIPandDebugLoc(llvm::IRBuilderBase &Builder,
                                  llvm::IRBuilderBase::InsertPoint IP) {
   Builder.restoreIP(IP);
+  // When IP points at a real instruction, restoreIP (SetInsertPoint) already
+  // set the debug location from that instruction, so leave it alone.
   llvm::BasicBlock *BB = Builder.GetInsertBlock();
-  llvm::BasicBlock::iterator I = Builder.GetInsertPoint();
-  if (!BB->empty() && I == BB->end())
+  if (Builder.GetInsertPoint() != BB->end())
+    return;
+
+  // At the end of a block, pick a location guaranteed to belong to the current
+  // insertion function's subprogram. Prefer the block's own last instruction;
+  // otherwise synthesize a location from the function's subprogram.
+  if (!BB->empty())
     Builder.SetCurrentDebugLocation(BB->back().getStableDebugLoc());
+  else if (llvm::DISubprogram *FSP =
+               BB->getParent() ? BB->getParent()->getSubprogram() : nullptr) {
+    unsigned Line = FSP->getScopeLine() ? FSP->getScopeLine() : FSP->getLine();
+    Builder.SetCurrentDebugLocation(
+        llvm::DILocation::get(FSP->getContext(), Line, /*Column=*/0, FSP));
+  }
 }
 
 static bool hasGridValue(const Triple &T) {
@@ -10843,7 +10858,7 @@ Error OpenMPIRBuilder::emitOffloadingArrays(
         CodeGenIP = Builder.saveIP();
         Builder.restoreIP(AllocaIP);
         Info.DevicePtrInfoMap[BPVal] = {BP, Builder.CreateAlloca(PtrTy)};
-        Builder.restoreIP(CodeGenIP);
+        restoreIPandDebugLoc(Builder, CodeGenIP);
         if (DeviceAddrCB)
           DeviceAddrCB(I, Info.DevicePtrInfoMap[BPVal].second);
       } else if (CombinedInfo.DevicePointers[I] == DeviceInfoTy::Address) {

diff  --git a/mlir/test/Target/LLVMIR/openmp-target-in-reduction-debug.mlir b/mlir/test/Target/LLVMIR/openmp-target-in-reduction-debug.mlir
new file mode 100644
index 0000000000000..55ca27f39d5ea
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-target-in-reduction-debug.mlir
@@ -0,0 +1,61 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// Regression test for debug-location preservation across offload-array codegen.
+//
+// When an omp.target is lowered for the host, OpenMPIRBuilder emits the host
+// fallback path that calls the outlined kernel stub directly. Building the
+// offload arrays (emitOffloadingArrays) temporarily moves the IRBuilder to the
+// alloca block, which clears the builder's current debug location. Before the
+// fix that location was never restored, so the inlinable fallback call to the
+// kernel stub was emitted with no !dbg attachment. In a function that has debug
+// info that call fails the verifier:
+//
+//   inlinable function call in a function with debug info must have a !dbg
+//   location
+//
+// The nesting below (parallel > taskgroup task_reduction > target in_reduction)
+// reproduces the exact state in which the location was dropped. This test pins
+// down that the host fallback call carries a debug location (and build does not
+// fail).
+
+#di_file = #llvm.di_file<"repro.f90" in "">
+#di_null_type = #llvm.di_null_type
+#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<id = distinct[1]<>, compileUnit = #cu, scope = #di_file, name = "foo", file = #di_file, subprogramFlags = "Definition", type = #sp_ty>
+#sp_tgt = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #di_file, name = "target_region", file = #di_file, subprogramFlags = "LocalToUnit|Definition", type = #sp_ty>
+#loc = loc("repro.f90":1:1)
+#loc_foo = loc(fused<#sp>[#loc])
+#loc_tgt = loc(fused<#sp_tgt>[#loc])
+
+module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu", omp.is_gpu = false, omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"], omp.version = #omp.version<version = 50>} {
+  omp.declare_reduction @add_reduction_i32 : i32 init {
+  ^bb0(%arg0: i32):
+    %0 = llvm.mlir.constant(0 : i32) : i32
+    omp.yield(%0 : i32)
+  } combiner {
+  ^bb0(%arg0: i32, %arg1: i32):
+    %0 = llvm.add %arg0, %arg1 : i32
+    omp.yield(%0 : i32)
+  }
+  llvm.func @foo_() {
+    %0 = llvm.mlir.constant(1 : i64) : i64
+    %1 = llvm.alloca %0 x i32 : (i64) -> !llvm.ptr
+    omp.parallel {
+      omp.taskgroup task_reduction(@add_reduction_i32 %1 -> %arg0 : !llvm.ptr) {
+        %2 = omp.map.info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(implicit, tofrom) capture(ByRef) -> !llvm.ptr {name = "sum"}
+        omp.target kernel_type(generic) in_reduction(@add_reduction_i32 %arg0 : !llvm.ptr) map_entries(%2 -> %arg1 : !llvm.ptr) {
+          %c1 = llvm.mlir.constant(1 : i32) : i32
+          llvm.store %c1, %arg1 : i32, !llvm.ptr
+          omp.terminator
+        } loc(#loc_tgt)
+        omp.terminator
+      }
+      omp.terminator
+    }
+    llvm.return
+  } loc(#loc_foo)
+}
+
+// CHECK-LABEL: define void @foo_(
+// CHECK: call void @__omp_offloading_{{.*}}_foo__{{.*}}(ptr %{{.+}}, ptr null), !dbg


        


More information about the Mlir-commits mailing list