[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