[llvm-branch-commits] [flang] [flang][OpenMP] Support lowering of metadirective (part 2) (PR #194424)

Abid Qadeer via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue May 26 02:25:57 PDT 2026


================
@@ -4629,35 +4638,83 @@ static void genMetadirective(lower::AbstractConverter &converter,
                    queue.begin());
   };
 
-  const parser::OmpDirectiveSpecification *selected = fallback;
-  if (candidates.size() == 1) {
-    selected = candidates.front().spec;
-  } else if (!candidates.empty()) {
+  auto selectBestCandidate =
+      [](llvm::ArrayRef<unsigned> candidateIndices,
+         llvm::ArrayRef<MetadirectiveCandidate> candidates,
+         const TargetOMPContext &ompCtx) -> std::optional<unsigned> {
+    if (candidateIndices.empty())
+      return std::nullopt;
+    if (candidateIndices.size() == 1)
+      return candidateIndices.front();
+
     // The OpenMP context scorer preserves input order for tied candidates.
     // Put explicit variants first so they take precedence over implicit
     // `nothing`, as required by metadirective selection.
     llvm::SmallVector<unsigned, 4> candidateOrder;
-    candidateOrder.reserve(candidates.size());
-    for (auto [idx, candidate] : llvm::enumerate(candidates))
-      if (candidate.isExplicit)
+    candidateOrder.reserve(candidateIndices.size());
+    for (unsigned idx : candidateIndices)
+      if (candidates[idx].isExplicit)
         candidateOrder.push_back(idx);
-    for (auto [idx, candidate] : llvm::enumerate(candidates))
-      if (!candidate.isExplicit)
+    for (unsigned idx : candidateIndices)
+      if (!candidates[idx].isExplicit)
         candidateOrder.push_back(idx);
 
     llvm::SmallVector<llvm::omp::VariantMatchInfo, 4> orderedVMIs;
-    orderedVMIs.reserve(candidates.size());
+    orderedVMIs.reserve(candidateOrder.size());
     for (unsigned idx : candidateOrder)
       orderedVMIs.push_back(candidates[idx].vmi);
 
     int bestIdx = llvm::omp::getBestVariantMatchForContext(orderedVMIs, ompCtx);
     if (bestIdx >= 0) {
       assert(static_cast<size_t>(bestIdx) < candidateOrder.size() &&
              "best variant index out of range");
-      selected = candidates[candidateOrder[bestIdx]].spec;
+      return candidateOrder[bestIdx];
+    }
+    return std::nullopt;
+  };
+
+  llvm::SmallVector<unsigned, 4> remainingCandidates;
+  remainingCandidates.reserve(candidates.size());
+  for (unsigned idx = 0, end = candidates.size(); idx < end; ++idx)
+    remainingCandidates.push_back(idx);
+
+  mlir::Location loc = converter.genLocation(clauseList.source);
+  lower::StatementContext stmtCtx;
+
+  while (!remainingCandidates.empty()) {
+    std::optional<unsigned> selected =
+        selectBestCandidate(remainingCandidates, candidates, ompCtx);
+    if (!selected) {
+      genVariant(fallback);
+      return;
+    }
+
+    const MetadirectiveCandidate &candidate = candidates[*selected];
+    if (!candidate.condExpr) {
+      genVariant(candidate.spec);
+      return;
     }
+
+    const auto *condExpr = semantics::GetExpr(semaCtx, *candidate.condExpr);
+    assert(condExpr && "missing expression for user condition");
+    mlir::Value condVal =
+        fir::getBase(converter.genExprValue(*condExpr, stmtCtx, &loc));
+
----------------
abidh wrote:

I think you need to call `stmtCtx.finalizeAndReset()` here to make sure any cleanups run at the correct location. Consider the following testcase. Without this call, the hlfir.end_associate is emitted in the wrong place.
```
subroutine test_dynamic_condition_with_cleanup()
  interface
    function getbool(s) result(r)
      character(*), intent(in) :: s
      logical :: r
    end function
  end interface
  !$omp metadirective &
  !$omp & when(user={condition(getbool("hello"))}: barrier) &
#ifdef OMP_52
  !$omp & otherwise(taskwait)
#else
  !$omp & default(taskwait)
#endif
end subroutine
```

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


More information about the llvm-branch-commits mailing list