[flang-commits] [flang] [llvm] [mlir] [openmp] [Flang][OpenMP] Lower scan directive and inscan reduction modifier (PR #206747)

via flang-commits flang-commits at lists.llvm.org
Mon Jul 27 14:49:07 PDT 2026


================
@@ -4685,21 +4843,99 @@ convertOmpWsloop(Operation &opInst, llvm::IRBuilderBase &builder,
   if (failed(handleError(regionBlock, opInst)))
     return failure();
 
+  // Generates the loop body for a worksharing loop, including linear-variable
+  // handling and the call into the OpenMPIRBuilder's worksharing-loop helper.
+  // For scan reductions this lambda is invoked twice: once for the input loop
+  // and once for the scan loop.
+  const auto &&wsloopCodeGen = [&](llvm::CanonicalLoopInfo *loopInfo,
+                                   bool noLoopMode,
+                                   bool inputScanLoop) -> LogicalResult {
+    // Emit Initialization and Update IR for linear variables
+    if (!wsloopOp.getLinearVars().empty()) {
+      linearClauseProcessor.initLinearVar(builder, moduleTranslation,
+                                          loopInfo->getPreheader());
+      llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterBarrierIP =
+          moduleTranslation.getOpenMPBuilder()->createBarrier(
+              builder, llvm::omp::OMPD_barrier);
+      if (failed(handleError(afterBarrierIP, *loopOp)))
+        return failure();
+      builder.restoreIP(*afterBarrierIP);
+      linearClauseProcessor.updateLinearVar(builder, loopInfo->getBody(),
+                                            loopInfo->getIndVar());
+      linearClauseProcessor.splitLinearFiniBB(builder, loopInfo->getExit());
+    }
+
+    builder.SetInsertPoint(*regionBlock, (*regionBlock)->begin());
+
+    for (size_t index = 0; index < wsloopOp.getLinearVars().size(); index++)
+      linearClauseProcessor.rewriteInPlace(builder, loopInfo->getBody(),
+                                           loopInfo->getLatch(), index);
+
+    // Scan reductions need a barrier at the end of the input (first) loop so
+    // that every thread has finished writing the temporary buffer before the
+    // masked prefix-sum reads it. A source-level `nowait` only elides the final
+    // barrier after the scan (second) loop, so force the barrier for the input
+    // loop regardless of `nowait` to avoid a data race.
+    bool needsBarrier = loopNeedsBarrier || (isInScanRegion && inputScanLoop);
----------------
chichunchen wrote:

Thanks for adding the mandatory barrier after the input loop, that fixes the race before the prefix
computation. There is still a buffer-lifetime race after the scan loop when nowait is present.

For the second loop, `needsBarrier` becomes false. `emitScanBasedDirectiveFinalsIR` then immediately enters a masked region and frees the shared scan buffer. The masked thread can therefore free it while another thread is still executing the second loop and may load a later prefix value from that buffer. The barrier emitted after the masked region is too late to protect those accesses. It also reintroduces end-of-construct synchronization despite nowait.

https://github.com/llvm/llvm-project/pull/206747


More information about the flang-commits mailing list