[flang-commits] [flang] [flang][OpenMP] Lower DO, SIMD, and DO SIMD metadirective variants (PR #218555)

via flang-commits flang-commits at lists.llvm.org
Wed Aug 26 11:59:30 PDT 2026


================
@@ -6822,23 +6834,402 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
 }
 
 namespace {
-struct MetadirectiveCandidate {
-  MetadirectiveCandidate(const parser::OmpDirectiveSpecification *spec,
-                         llvm::omp::VariantMatchInfo vmi, bool isExplicit,
-                         std::optional<semantics::omp::DynamicUserCondition>
-                             dynamicCond = std::nullopt,
-                         bool conditionShouldBeTrue = true)
-      : spec(spec), vmi(vmi), isExplicit(isExplicit), dynamicCond(dynamicCond),
-        conditionShouldBeTrue(conditionShouldBeTrue) {}
-
-  const parser::OmpDirectiveSpecification *spec = nullptr;
-  llvm::omp::VariantMatchInfo vmi;
-  bool isExplicit = false;
-  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
 
+static bool isSupportedMetadirectiveLoopCompilerDirective(
+    const parser::CompilerDirective &directive) {
+  // Only directives known not to emit executable operations may be processed
+  // before runtime selection. New variants remain unsupported until classified.
+  using SupportedDirectives = std::tuple<
+      std::list<parser::CompilerDirective::IgnoreTKR>,
+      parser::CompilerDirective::LoopCount,
+      std::list<parser::CompilerDirective::AssumeAligned>,
+      parser::CompilerDirective::VectorAlways,
+      parser::CompilerDirective::VectorLength,
+      std::list<parser::CompilerDirective::NameValue>,
+      parser::CompilerDirective::Unroll,
+      parser::CompilerDirective::UnrollAndJam,
+      parser::CompilerDirective::Unrecognized,
+      parser::CompilerDirective::NoVector, parser::CompilerDirective::NoUnroll,
+      parser::CompilerDirective::NoUnrollAndJam,
+      parser::CompilerDirective::ForceInline, parser::CompilerDirective::Inline,
+      parser::CompilerDirective::NoInline,
+      parser::CompilerDirective::InlineAlways, parser::CompilerDirective::IVDep,
+      parser::CompilerDirective::Simd>;
+
+  return common::visit(
+      [](const auto &value) {
+        using T = std::decay_t<decltype(value)>;
+        return common::HasMember<T, SupportedDirectives>;
+      },
+      directive.u);
+}
+
+static bool
+isIgnorableMetadirectiveLoopAssociationEval(lower::pft::Evaluation &eval) {
+  const auto *directive = eval.getIf<parser::CompilerDirective>();
+  return eval.isEndStmt() ||
+         (directive &&
+          isSupportedMetadirectiveLoopCompilerDirective(*directive));
+}
+
+static bool
+isUnsupportedMetadirectiveLoopAssociationEval(lower::pft::Evaluation &eval) {
+  if (const auto *directive = eval.getIf<parser::CompilerDirective>())
+    return !isSupportedMetadirectiveLoopCompilerDirective(*directive);
+  return eval.isOtherStmt() ||
+         (eval.isDirective() && !eval.isExecutableDirective());
+}
+
+/// 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,
+    lower::pft::Evaluation **unsupportedInterveningEval = nullptr) {
+  if (unsupportedInterveningEval)
+    *unsupportedInterveningEval = nullptr;
+
+  if (eval.hasNestedEvaluations()) {
+    auto nestedIt =
+        llvm::find_if(eval.getNestedEvaluations(), [](auto &nested) {
+          return !isIgnorableMetadirectiveLoopAssociationEval(nested);
+        });
+    if (nestedIt != eval.getNestedEvaluations().end()) {
+      if (nestedIt->getIf<parser::DoConstruct>())
+        return &*nestedIt;
+      if (unsupportedInterveningEval &&
+          isUnsupportedMetadirectiveLoopAssociationEval(*nestedIt))
+        *unsupportedInterveningEval = &*nestedIt;
----------------
MattPD wrote:

Confirmed, the nested association cases are now covered.

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


More information about the flang-commits mailing list