[flang-commits] [flang] [flang][OpenMP] Lower DO and SIMD variants in metadirectives (PR #210810)
via flang-commits
flang-commits at lists.llvm.org
Fri Jul 24 22:55:07 PDT 2026
================
@@ -5853,8 +5855,296 @@ struct MetadirectiveCandidate {
std::optional<semantics::omp::DynamicUserCondition> dynamicCond;
bool conditionShouldBeTrue = true;
};
+
+struct SplicedAssociatedEvaluations {
+ using Iterator = lower::pft::EvaluationList::iterator;
+
+ void record(lower::pft::EvaluationList &parent, Iterator evaluation) {
+ assert((!parentList || parentList == &parent) &&
+ "associated evaluations have different parents");
+ parentList = &parent;
+ evaluations.emplace_back(evaluation, std::next(evaluation));
+ }
+
+ void restore(lower::pft::EvaluationList &nested) {
+ if (evaluations.empty())
+ return;
+ assert(parentList && "missing parent evaluation list");
+ // A saved successor may also have been spliced. Restore in reverse order
+ // so every insertion point is back in the parent list before it is used.
+ for (auto &entry : llvm::reverse(evaluations)) {
+ entry.first->skipNextLowering = true;
+ parentList->splice(entry.second, nested, entry.first);
+ }
+ if (entryEvaluation) {
+ entryEvaluation->isNewBlock = true;
+ entryEvaluation->block = entryBlock;
+ }
+ }
+
+ void suppressEntryBlock(lower::pft::Evaluation &evaluation) {
+ assert(!entryEvaluation && evaluation.isNewBlock && evaluation.block &&
+ "invalid associated entry evaluation");
+ // Do not let either cloned loop arm enter a function-region block. The
+ // metadirective selection will be placed in this block for an active ENTRY.
+ entryEvaluation = &evaluation;
+ entryBlock = evaluation.block;
+ evaluation.isNewBlock = false;
+ evaluation.block = nullptr;
+ }
+
+ mlir::Block *getEntryBlock() const { return entryBlock; }
+
+private:
+ lower::pft::EvaluationList *parentList = nullptr;
+ llvm::SmallVector<std::pair<Iterator, Iterator>, 4> evaluations;
+ lower::pft::Evaluation *entryEvaluation = nullptr;
+ mlir::Block *entryBlock = nullptr;
+};
} // namespace
+/// A loop-associated metadirective is lowered like a real loop construct, but
+/// the PFT leaves its associated loop nest as the following sibling instead of
+/// nesting it underneath. Splice that sibling into the metadirective's own
+/// nested evaluations so the shared loop-lowering path can find it. Return
+/// nullptr if no associated DO loop follows.
+static lower::pft::Evaluation *spliceAssociatedDoEval(
+ lower::pft::Evaluation &eval,
+ SplicedAssociatedEvaluations *splicedEvaluations = nullptr) {
+ if (eval.hasNestedEvaluations()) {
+ auto nestedIt =
+ llvm::find_if(eval.getNestedEvaluations(), [](auto &nested) {
+ return !nested.isEndStmt() &&
+ !nested.template getIf<parser::CompilerDirective>();
+ });
+ if (nestedIt != eval.getNestedEvaluations().end())
+ return nestedIt->getIf<parser::DoConstruct>() ? &*nestedIt : nullptr;
+ return nullptr;
+ }
+
+ // A metadirective in a specification part (e.g. at module scope) has no
+ // parent construct and no owning procedure, so there is no sibling list.
+ lower::pft::FunctionLikeUnit *owningProc = eval.getOwningProcedure();
+ if (!eval.parentConstruct && !owningProc)
+ return nullptr;
+ auto *parentList = eval.parentConstruct
+ ? eval.parentConstruct->evaluationList.get()
+ : &owningProc->evaluationList;
+ auto metaIt = llvm::find_if(
+ *parentList, [&](lower::pft::Evaluation &e) { return &e == &eval; });
+ assert(metaIt != parentList->end() &&
+ "metadirective eval not found in parent list");
+
+ auto firstAssociatedIt = std::next(metaIt);
+ auto loopIt = firstAssociatedIt;
+ while (loopIt != parentList->end() &&
+ (loopIt->isEndStmt() || loopIt->getIf<parser::CompilerDirective>()))
----------------
MattPD wrote:
This scan advances past only end statements and compiler directives, so a declarative OpenMP sibling between the metadirective and its loop (e.g., `!$omp threadprivate(x)`) stops the scan, and lowering later reports `loop-associated METADIRECTIVE without associated DO` even though the loop is present. Semantics currently accepts this interleaving for a metadirective, whereas a real `!$omp do` with an intervening `threadprivate` is rejected (`expected OpenMP construct`). Should the merged metadirective loop-nest semantic check reject an intervening declarative construct the way the ordinary loop directives do, so this becomes a clear diagnostic instead of a misleading lowering TODO?
https://github.com/llvm/llvm-project/pull/210810
More information about the flang-commits
mailing list