[Mlir-commits] [llvm] [mlir] Reland [OMPIRBuilder] Don't use invalid debug loc in reduction fn. (PR #211566)

Abid Qadeer llvmlistbot at llvm.org
Thu Jul 23 07:24:32 PDT 2026


https://github.com/abidh created https://github.com/llvm/llvm-project/pull/211566

This fixes https://github.com/llvm/llvm-project/issues/211385. This was initially landed in https://github.com/llvm/llvm-project/pull/148284.

We have this pattern of code in OMPIRBuilder for many functions that are used in reduction operations.

 ```
 Function *LtGRFunc = Function::Create
  BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", LtGRFunc);
  Builder.SetInsertPoint(EntryBlock);
```

The insertion point is moved to the new function but the debug location
is not updated. This means that reduction function will use the debug
location that points to another function. This problem gets hidden
because these functions gets inlined but the potential for failure
exists.

This patch resets the debug location when insertion point is moved to new
function. Some `InsertPointGuard` have been added to make sure we restore
the debug location correctly when we are done with the reduction function.

It also clears the debug location for the helper-internal barriers in
emitInterWarpCopyFunction.

>From 5c789ea6a6969bb82e41694624bfbbc90542bcba Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Thu, 23 Jul 2026 14:33:11 +0100
Subject: [PATCH] Reland [OMPIRBuilder] Don't use invalid debug loc in
 reduction functions.

We have this pattern of code in OMPIRBuilder for many functions that are
used in reduction operations.

 ```
 Function *LtGRFunc = Function::Create
  BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", LtGRFunc);
  Builder.SetInsertPoint(EntryBlock);
```

The insertion point is moved to the new function but the debug location
is not updated. This means that reduction function will use the debug
location that points to another function. This problem gets hidden
because these functions gets inlined but the potential for failure
exists.

This patch resets the debug location when insertion point is moved to new
function. Some `InsertPointGuard` have been added to make sure we restore
the debug location correctly when we are done with the reduction function.

It also clears the debug location for the helper-internal barriers in
emitInterWarpCopyFunction. Those barriers were created with the enclosing
construct's debug location, which updateToLocation leaves set on the
builder, so instructions emitted afterwards in the helper would otherwise
inherit a location scoped to the caller's (kernel) subprogram.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp     | 30 ++++----
 .../LLVMIR/omptarget-debug-reduc-fn-loc.mlir  | 71 +++++++++++++++++++
 2 files changed, 89 insertions(+), 12 deletions(-)
 create mode 100644 mlir/test/Target/LLVMIR/omptarget-debug-reduc-fn-loc.mlir

diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index fb1cebf28b95b..57e199bdff09a 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -3526,7 +3526,7 @@ Error OpenMPIRBuilder::emitReductionListCopy(
 Expected<Function *> OpenMPIRBuilder::emitInterWarpCopyFunction(
     const LocationDescription &Loc, ArrayRef<ReductionInfo> ReductionInfos,
     AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
-  InsertPointTy SavedIP = Builder.saveIP();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   LLVMContext &Ctx = M.getContext();
   FunctionType *FuncTy = FunctionType::get(
       Builder.getVoidTy(), {Builder.getPtrTy(), Builder.getInt32Ty()},
@@ -3540,6 +3540,7 @@ Expected<Function *> OpenMPIRBuilder::emitInterWarpCopyFunction(
   WcFunc->addParamAttr(1, Attribute::NoUndef);
   BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "entry", WcFunc);
   Builder.SetInsertPoint(EntryBB);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // ReduceList: thread local Reduce list.
   // At the stage of the computation when this function is called, partially
@@ -3646,7 +3647,7 @@ Expected<Function *> OpenMPIRBuilder::emitInterWarpCopyFunction(
 
       // kmpc_barrier.
       InsertPointOrErrorTy BarrierIP1 =
-          createBarrier(LocationDescription(Builder.saveIP(), Loc.DL),
+          createBarrier(LocationDescription(Builder.saveIP(), DebugLoc()),
                         omp::Directive::OMPD_unknown,
                         /* ForceSimpleCall */ false,
                         /* CheckCancelFlag */ true);
@@ -3705,7 +3706,7 @@ Expected<Function *> OpenMPIRBuilder::emitInterWarpCopyFunction(
       // endif
       emitBlock(MergeBB, Builder.GetInsertBlock()->getParent());
       InsertPointOrErrorTy BarrierIP2 =
-          createBarrier(LocationDescription(Builder.saveIP(), Loc.DL),
+          createBarrier(LocationDescription(Builder.saveIP(), DebugLoc()),
                         omp::Directive::OMPD_unknown,
                         /* ForceSimpleCall */ false,
                         /* CheckCancelFlag */ true);
@@ -3778,7 +3779,6 @@ Expected<Function *> OpenMPIRBuilder::emitInterWarpCopyFunction(
   }
 
   Builder.CreateRetVoid();
-  Builder.restoreIP(SavedIP);
 
   return WcFunc;
 }
@@ -3787,6 +3787,7 @@ Expected<Function *> OpenMPIRBuilder::emitShuffleAndReduceFunction(
     ArrayRef<ReductionInfo> ReductionInfos, Function *ReduceFn,
     AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
   LLVMContext &Ctx = M.getContext();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   FunctionType *FuncTy =
       FunctionType::get(Builder.getVoidTy(),
                         {Builder.getPtrTy(), Builder.getInt16Ty(),
@@ -3806,6 +3807,7 @@ Expected<Function *> OpenMPIRBuilder::emitShuffleAndReduceFunction(
   SarFunc->addParamAttr(3, Attribute::SExt);
   BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "entry", SarFunc);
   Builder.SetInsertPoint(EntryBB);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Thread local Reduce list used to host the values of data to be reduced.
   Argument *ReduceListArg = SarFunc->getArg(0);
@@ -4018,7 +4020,7 @@ Expected<Value *> OpenMPIRBuilder::createReductionDescriptorCopy(
 Expected<Function *> OpenMPIRBuilder::emitListToGlobalCopyFunction(
     ArrayRef<ReductionInfo> ReductionInfos, Type *ReductionsBufferTy,
     AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
-  OpenMPIRBuilder::InsertPointTy OldIP = Builder.saveIP();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   LLVMContext &Ctx = M.getContext();
   FunctionType *FuncTy = FunctionType::get(
       Builder.getVoidTy(),
@@ -4034,6 +4036,7 @@ Expected<Function *> OpenMPIRBuilder::emitListToGlobalCopyFunction(
 
   BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", LtGCFunc);
   Builder.SetInsertPoint(EntryBlock);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Buffer: global reduction buffer.
   Argument *BufferArg = LtGCFunc->getArg(0);
@@ -4137,14 +4140,13 @@ Expected<Function *> OpenMPIRBuilder::emitListToGlobalCopyFunction(
   }
 
   Builder.CreateRetVoid();
-  Builder.restoreIP(OldIP);
   return LtGCFunc;
 }
 
 Expected<Function *> OpenMPIRBuilder::emitListToGlobalReduceFunction(
     ArrayRef<ReductionInfo> ReductionInfos, Function *ReduceFn,
     Type *ReductionsBufferTy, AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
-  OpenMPIRBuilder::InsertPointTy OldIP = Builder.saveIP();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   LLVMContext &Ctx = M.getContext();
   FunctionType *FuncTy = FunctionType::get(
       Builder.getVoidTy(),
@@ -4160,6 +4162,7 @@ Expected<Function *> OpenMPIRBuilder::emitListToGlobalReduceFunction(
 
   BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", LtGRFunc);
   Builder.SetInsertPoint(EntryBlock);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Buffer: global reduction buffer.
   Argument *BufferArg = LtGRFunc->getArg(0);
@@ -4245,14 +4248,13 @@ Expected<Function *> OpenMPIRBuilder::emitListToGlobalReduceFunction(
   createRuntimeFunctionCall(ReduceFn, {LocalReduceListAddrCast, ReduceList})
       ->addFnAttr(Attribute::NoUnwind);
   Builder.CreateRetVoid();
-  Builder.restoreIP(OldIP);
   return LtGRFunc;
 }
 
 Expected<Function *> OpenMPIRBuilder::emitGlobalToListCopyFunction(
     ArrayRef<ReductionInfo> ReductionInfos, Type *ReductionsBufferTy,
     AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
-  OpenMPIRBuilder::InsertPointTy OldIP = Builder.saveIP();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   LLVMContext &Ctx = M.getContext();
   FunctionType *FuncTy = FunctionType::get(
       Builder.getVoidTy(),
@@ -4268,6 +4270,7 @@ Expected<Function *> OpenMPIRBuilder::emitGlobalToListCopyFunction(
 
   BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", GtLCFunc);
   Builder.SetInsertPoint(EntryBlock);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Buffer: global reduction buffer.
   Argument *BufferArg = GtLCFunc->getArg(0);
@@ -4368,14 +4371,13 @@ Expected<Function *> OpenMPIRBuilder::emitGlobalToListCopyFunction(
   }
 
   Builder.CreateRetVoid();
-  Builder.restoreIP(OldIP);
   return GtLCFunc;
 }
 
 Expected<Function *> OpenMPIRBuilder::emitGlobalToListReduceFunction(
     ArrayRef<ReductionInfo> ReductionInfos, Function *ReduceFn,
     Type *ReductionsBufferTy, AttributeList FuncAttrs, ArrayRef<bool> IsByRef) {
-  OpenMPIRBuilder::InsertPointTy OldIP = Builder.saveIP();
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   LLVMContext &Ctx = M.getContext();
   auto *FuncTy = FunctionType::get(
       Builder.getVoidTy(),
@@ -4391,6 +4393,7 @@ Expected<Function *> OpenMPIRBuilder::emitGlobalToListReduceFunction(
 
   BasicBlock *EntryBlock = BasicBlock::Create(Ctx, "entry", GtLRFunc);
   Builder.SetInsertPoint(EntryBlock);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Buffer: global reduction buffer.
   Argument *BufferArg = GtLRFunc->getArg(0);
@@ -4476,7 +4479,6 @@ Expected<Function *> OpenMPIRBuilder::emitGlobalToListReduceFunction(
   createRuntimeFunctionCall(ReduceFn, {ReduceList, ReductionList})
       ->addFnAttr(Attribute::NoUnwind);
   Builder.CreateRetVoid();
-  Builder.restoreIP(OldIP);
   return GtLRFunc;
 }
 
@@ -4490,6 +4492,7 @@ Expected<Function *> OpenMPIRBuilder::createReductionFunction(
     StringRef ReducerName, ArrayRef<ReductionInfo> ReductionInfos,
     ArrayRef<bool> IsByRef, ReductionGenCBKind ReductionGenCBKind,
     AttributeList FuncAttrs) {
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   auto *FuncTy = FunctionType::get(Builder.getVoidTy(),
                                    {Builder.getPtrTy(), Builder.getPtrTy()},
                                    /* IsVarArg */ false);
@@ -4503,6 +4506,7 @@ Expected<Function *> OpenMPIRBuilder::createReductionFunction(
   BasicBlock *EntryBB =
       BasicBlock::Create(M.getContext(), "entry", ReductionFunc);
   Builder.SetInsertPoint(EntryBB);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
 
   // Need to alloca memory here and deal with the pointers before getting
   // LHS/RHS pointers out
@@ -4986,10 +4990,12 @@ static Error populateReductionFunction(
     Function *ReductionFunc,
     ArrayRef<OpenMPIRBuilder::ReductionInfo> ReductionInfos,
     IRBuilder<> &Builder, ArrayRef<bool> IsByRef, bool IsGPU) {
+  IRBuilder<>::InsertPointGuard IPG(Builder);
   Module *Module = ReductionFunc->getParent();
   BasicBlock *ReductionFuncBlock =
       BasicBlock::Create(Module->getContext(), "", ReductionFunc);
   Builder.SetInsertPoint(ReductionFuncBlock);
+  Builder.SetCurrentDebugLocation(llvm::DebugLoc());
   Value *LHSArrayPtr = nullptr;
   Value *RHSArrayPtr = nullptr;
   if (IsGPU) {
diff --git a/mlir/test/Target/LLVMIR/omptarget-debug-reduc-fn-loc.mlir b/mlir/test/Target/LLVMIR/omptarget-debug-reduc-fn-loc.mlir
new file mode 100644
index 0000000000000..689446eee8de9
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/omptarget-debug-reduc-fn-loc.mlir
@@ -0,0 +1,71 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// The device reduction helpers emitted by OpenMPIRBuilder have no debug info of
+// their own. If the builder's current debug location is left set while their
+// bodies are emitted, their instructions get DILocations scoped to the
+// wrong subprogram. Check that none of the GPU reduction helpers carry a
+// !dbg attachment.
+
+#di_file = #llvm.di_file<"repro.f90" in "">
+#di_null_type = #llvm.di_null_type
+#loc1 = loc("repro.f90":1:1)
+#loc2 = loc("repro.f90":7:9)
+#di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang", isOptimized = true, emissionKind = Full>
+#di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_null_type>
+#di_subprogram = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "k", linkageName = "k_", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
+#di_subprogram1 = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "__omp_offloading_k_l7", linkageName = "__omp_offloading_k_l7", file = #di_file, line = 7, scopeLine = 7, subprogramFlags = "LocalToUnit|Definition|Optimized", type = #di_subroutine_type>
+#loc14 = loc(fused<#di_subprogram>[#loc1])
+#loc15 = loc(fused<#di_subprogram1>[#loc2])
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, !llvm.ptr<1> = dense<64> : vector<4xi64>, !llvm.ptr<5> = dense<32> : vector<4xi64>, i64 = dense<64> : vector<2xi64>, "dlti.alloca_memory_space" = 5 : ui64, "dlti.global_memory_space" = 1 : ui64>, llvm.target_triple = "amdgcn-amd-amdhsa", omp.is_gpu = true, omp.is_target_device = true, omp.version = #omp.version<version = 31>} {
+  omp.declare_reduction @add_reduction_f64 : f64 init {
+  ^bb0(%arg0: f64):
+    %0 = llvm.mlir.constant(0.000000e+00 : f64) : f64 loc(#loc2)
+    omp.yield(%0 : f64) loc(#loc2)
+  } combiner {
+  ^bb0(%arg0: f64, %arg1: f64):
+    %0 = llvm.fadd %arg0, %arg1 : f64 loc(#loc2)
+    omp.yield(%0 : f64) loc(#loc2)
+  } loc(#loc2)
+  llvm.func @k_(%arg0: !llvm.ptr) {
+    %1 = omp.map.info var_ptr(%arg0 : !llvm.ptr, f64) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = "s"} loc(#loc2)
+    omp.target kernel_type(spmd) map_entries(%1 -> %arg1 : !llvm.ptr) {
+      %c1 = llvm.mlir.constant(1 : i32) : i32 loc(#loc2)
+      %cn = llvm.mlir.constant(1024 : i32) : i32 loc(#loc2)
+      omp.teams reduction(@add_reduction_f64 %arg1 -> %arg2 : !llvm.ptr) {
+        omp.parallel {
+          omp.distribute {
+            omp.wsloop reduction(@add_reduction_f64 %arg2 -> %arg3 : !llvm.ptr) {
+              omp.loop_nest (%arg4) : i32 = (%c1) to (%cn) inclusive step (%c1) {
+                %2 = llvm.load %arg3 : !llvm.ptr -> f64 loc(#loc2)
+                %cst = llvm.mlir.constant(1.000000e+00 : f64) : f64 loc(#loc2)
+                %3 = llvm.fadd %2, %cst : f64 loc(#loc2)
+                llvm.store %3, %arg3 : f64, !llvm.ptr loc(#loc2)
+                omp.yield loc(#loc2)
+              } loc(#loc2)
+            } {omp.composite} loc(#loc2)
+          } {omp.composite} loc(#loc2)
+          omp.terminator loc(#loc2)
+        } {omp.composite} loc(#loc2)
+        omp.terminator loc(#loc2)
+      } {omp.combined} loc(#loc2)
+      omp.terminator loc(#loc2)
+    } {omp.combined} loc(#loc15)
+    llvm.return loc(#loc14)
+  } loc(#loc14)
+} loc(#loc1)
+
+// CHECK-LABEL: define internal void @_omp_reduction_shuffle_and_reduce_func(
+// CHECK-NOT:     !dbg
+// CHECK:       }
+// CHECK-LABEL: define internal void @_omp_reduction_inter_warp_copy_func(
+// CHECK-NOT:     !dbg
+// CHECK:       }
+// CHECK-LABEL: define internal void @_omp_reduction_list_to_global_copy_func(
+// CHECK-NOT:     !dbg
+// CHECK:       }
+// CHECK-LABEL: define internal void @_omp_reduction_global_to_list_copy_func(
+// CHECK-NOT:     !dbg
+// CHECK:       }
+// CHECK-LABEL: define internal void @_omp_reduction_global_to_list_reduce_func(
+// CHECK-NOT:     !dbg
+// CHECK:       }



More information about the Mlir-commits mailing list