[flang-commits] [flang] [mlir] [mlir][OpenMP] Model memory effects of omp.section and omp.sections (PR #230167)
via flang-commits
flang-commits at lists.llvm.org
Fri Oct 9 04:10:21 PDT 2026
================
@@ -3258,6 +3258,100 @@ LogicalResult SectionsOp::verifyRegions() {
return success();
}
+/// Return whether all operations in the op's regions are memory-effect-free.
+static bool areRegionsMemoryEffectFree(Operation *op) {
+ for (Region ®ion : op->getRegions())
+ for (Operation &nestedOp : region.getOps())
+ if (!isMemoryEffectFree(&nestedOp))
+ return false;
+ return true;
+}
+
+/// Model private storage and the effects of referenced privatisation recipes.
+template <typename OpType>
+static void getPrivatisationEffects(
+ OpType op, SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+ std::optional<ArrayAttr> privateSyms = op.getPrivateSyms();
+ if (!privateSyms)
+ return;
+
+ MutableOperandRange privateVars = op.getPrivateVarsMutable();
+ auto iface = cast<BlockArgOpenMPOpInterface>(op.getOperation());
+ Block::BlockArgListType privateArgs = iface.getPrivateBlockArgs();
+ for (auto entry : llvm::zip_equal(privateVars, privateArgs, *privateSyms)) {
+ OpOperand &original = std::get<0>(entry);
+ BlockArgument privateCopy = std::get<1>(entry);
+
+ effects.emplace_back(MemoryEffects::Allocate::get(), privateCopy);
+ effects.emplace_back(MemoryEffects::Free::get(), privateCopy);
+ // private variables may read the original as a mold
+ effects.emplace_back(MemoryEffects::Read::get(), &original);
+
+ auto privateSym = cast<SymbolRefAttr>(std::get<2>(entry));
+ auto privatiser =
+ SymbolTable::lookupNearestSymbolFrom<PrivateClauseOp>(op, privateSym);
+ // RecursiveMemoryEffects only covers regions nested in the directive, not
+ // symbol-referenced regions, user defined types have arbitrary recipe bodies.
+ // Default to a conservative model of read and write to arbitrary memory.
+ if (!privatiser || !areRegionsMemoryEffectFree(privatiser)) {
+ effects.emplace_back(MemoryEffects::Read::get());
+ effects.emplace_back(MemoryEffects::Write::get());
+ }
+ }
+}
+
+void SectionsOp::getEffects(
+ llvm::SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
+ &effects) {
+ // TODO: Nowait does not eliminate an implicit barrier if the reduction clause
+ // is also present
+ if (!getNowait() || (!getReductionVarsMutable().empty() && getNowait())) {
+ effects.emplace_back(MemoryEffects::Read::get());
+ effects.emplace_back(MemoryEffects::Write::get());
+ }
+
+ getPrivatisationEffects(*this, effects);
+ auto iface = cast<BlockArgOpenMPOpInterface>(getOperation());
+ // We cannot determine if the variable is lastprivate, so assume all privates
+ // are.
+ for (auto entry :
+ llvm::zip_equal(getPrivateVarsMutable(), iface.getPrivateBlockArgs())) {
+ effects.emplace_back(MemoryEffects::Read::get(), std::get<1>(entry));
+ effects.emplace_back(MemoryEffects::Write::get(), &std::get<0>(entry));
----------------
JRP-arm wrote:
> In that case global effects are added if there are non-trivial effects for regions of the privatization declare op.
I'm not sure I fully understand this sentence so I'll explain my thinking.
Within `getPrivatisationEffects` we look at the recipes for all private variables and add their effects as if they were a firstprivate variable.
Then in `getLastprivateEffects` we add the lastprivate specific effects (writing the final value to the original variable).
I don't fully describe lastprivate effects in `getLastprivateEffects` to avoid duplicate effects since we always need to call `getPrivatisationEffects` alongside `getLastprivateEffects`.
https://github.com/llvm/llvm-project/pull/230167
More information about the flang-commits
mailing list