[flang-commits] [flang] 094bbde - [flang][OpenMP] NFC: Move trait-matching helpers to Semantics (#201584)

via flang-commits flang-commits at lists.llvm.org
Fri Jun 5 03:59:54 PDT 2026


Author: Abid Qadeer
Date: 2026-06-05T11:59:49+01:00
New Revision: 094bbde3e86c5b7890e162afe6d32957153565b6

URL: https://github.com/llvm/llvm-project/commit/094bbde3e86c5b7890e162afe6d32957153565b6
DIFF: https://github.com/llvm/llvm-project/commit/094bbde3e86c5b7890e162afe6d32957153565b6.diff

LOG: [flang][OpenMP] NFC: Move trait-matching helpers to Semantics (#201584)

Move the five trait-matching functions (`mapTraitSet`,
`mapTraitSelector`, `evaluateUserCondition`, `getTraitScore`,
`processTraitProperties`) that back metadirective lowering out of
Lower/OpenMP/Utils.cpp and into Semantics/openmp-utils.

These functions only operate on parsed OpenMP trait selectors and the
Fortran evaluate/folding machinery and carry no MLIR or lowering
dependency. Placing them in Semantics makes them reusable from the
semantic-recording phase of `declare variant` (and any other feature
that needs to build a `VariantMatchInfo`).

In Utils.cpp, the four pure mapping/folding functions are removed
entirely; their callers now call the Semantics versions directly. The
`processTraitProperties` is kept as a local wrapper to generate a TODO
error on Clause and extension properties.

---------

Co-authored-by: Cursor <cursoragent at cursor.com>

Added: 
    

Modified: 
    flang/include/flang/Semantics/openmp-utils.h
    flang/lib/Lower/OpenMP/Utils.cpp
    flang/lib/Lower/OpenMP/Utils.h
    flang/lib/Semantics/openmp-utils.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index c2e89fe829ce0..1ef8f9616ce64 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -22,7 +22,9 @@
 #include "flang/Parser/tools.h"
 #include "flang/Semantics/tools.h"
 
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/Frontend/OpenMP/OMPContext.h"
 
 #include <memory>
 #include <optional>
@@ -370,6 +372,37 @@ struct LoopSequence {
   std::vector<LoopSequence> children_;
   SemanticsContext *semaCtx_{nullptr};
 };
+
+// ---------------------------------------------------------------------------
+// Trait-matching helpers shared between metadirective lowering and
+// declare-variant semantic recording.
+// ---------------------------------------------------------------------------
+
+/// Map a parsed trait-set name to the corresponding LLVM OMP TraitSet enum.
+llvm::omp::TraitSet MapTraitSet(parser::OmpTraitSetSelectorName::Value name);
+
+/// Map a parsed trait-selector name (plus its containing set) to the
+/// corresponding LLVM OMP TraitSelector enum.
+llvm::omp::TraitSelector MapTraitSelector(
+    const parser::OmpTraitSelectorName &name, llvm::omp::TraitSet set);
+
+/// Try to constant-fold a user condition expression to a boolean.
+std::optional<bool> EvaluateUserCondition(
+    SemanticsContext &semaCtx, const parser::ScalarExpr &scalarExpr);
+
+/// Extract the optional score value from trait properties.
+llvm::APInt *GetTraitScore(
+    const std::optional<parser::OmpTraitSelector::Properties> &props,
+    SemanticsContext &semaCtx, std::optional<llvm::APInt> &scoreStorage);
+
+/// Collect trait property names (vendor, kind, arch, isa, etc.) into a VMI.
+/// Non-name properties (clause, extension) are silently skipped; the caller is
+/// responsible for diagnosing them before invoking this function.
+void ProcessTraitProperties(llvm::omp::VariantMatchInfo &vmi,
+    llvm::omp::TraitSet set, llvm::omp::TraitSelector selector,
+    const std::optional<parser::OmpTraitSelector::Properties> &props,
+    llvm::APInt *scorePtr);
+
 } // namespace omp
 } // namespace Fortran::semantics
 

diff  --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 4f6bc3610ad32..219115cbe8d4b 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -28,6 +28,7 @@
 #include <flang/Parser/openmp-utils.h>
 #include <flang/Parser/parse-tree.h>
 #include <flang/Parser/tools.h>
+#include <flang/Semantics/openmp-utils.h>
 #include <flang/Semantics/tools.h>
 #include <flang/Semantics/type.h>
 #include <flang/Utils/OpenMP.h>
@@ -1130,59 +1131,6 @@ mlir::Value genIteratorCoordinate(Fortran::lower::AbstractConverter &converter,
                                   /*typeparams=*/mlir::ValueRange{});
 }
 
-llvm::omp::TraitSet mapTraitSet(parser::OmpTraitSetSelectorName::Value name) {
-  switch (name) {
-  case parser::OmpTraitSetSelectorName::Value::Construct:
-    return llvm::omp::TraitSet::construct;
-  case parser::OmpTraitSetSelectorName::Value::Device:
-    return llvm::omp::TraitSet::device;
-  case parser::OmpTraitSetSelectorName::Value::Implementation:
-    return llvm::omp::TraitSet::implementation;
-  case parser::OmpTraitSetSelectorName::Value::User:
-    return llvm::omp::TraitSet::user;
-  case parser::OmpTraitSetSelectorName::Value::Target_Device:
-    return llvm::omp::TraitSet::target_device;
-  }
-  llvm_unreachable("unknown trait set");
-}
-
-llvm::omp::TraitSelector
-mapTraitSelector(const parser::OmpTraitSelectorName &name,
-                 llvm::omp::TraitSet set) {
-  if (const auto *val =
-          std::get_if<parser::OmpTraitSelectorName::Value>(&name.u)) {
-    switch (*val) {
-    case parser::OmpTraitSelectorName::Value::Kind:
-      if (set == llvm::omp::TraitSet::target_device)
-        return llvm::omp::TraitSelector::target_device_kind;
-      return llvm::omp::TraitSelector::device_kind;
-    case parser::OmpTraitSelectorName::Value::Arch:
-      if (set == llvm::omp::TraitSet::target_device)
-        return llvm::omp::TraitSelector::target_device_arch;
-      return llvm::omp::TraitSelector::device_arch;
-    case parser::OmpTraitSelectorName::Value::Isa:
-      if (set == llvm::omp::TraitSet::target_device)
-        return llvm::omp::TraitSelector::target_device_isa;
-      return llvm::omp::TraitSelector::device_isa;
-    case parser::OmpTraitSelectorName::Value::Vendor:
-      return llvm::omp::TraitSelector::implementation_vendor;
-    case parser::OmpTraitSelectorName::Value::Extension:
-      return llvm::omp::TraitSelector::implementation_extension;
-    case parser::OmpTraitSelectorName::Value::Condition:
-      return llvm::omp::TraitSelector::user_condition;
-    case parser::OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
-    case parser::OmpTraitSelectorName::Value::Requires:
-    case parser::OmpTraitSelectorName::Value::Simd:
-    case parser::OmpTraitSelectorName::Value::Device_Num:
-    case parser::OmpTraitSelectorName::Value::Uid:
-      break;
-    }
-  }
-  // Construct traits, extension strings, and remaining selectors use
-  // string-based lookup.
-  return llvm::omp::getOpenMPContextTraitSelectorKind(name.ToString(), set);
-}
-
 /// Collect trait property names (vendor, kind, arch, isa, etc.) into a VMI.
 static void processTraitProperties(
     llvm::omp::VariantMatchInfo &vmi, llvm::omp::TraitSet set,
@@ -1200,47 +1148,8 @@ static void processTraitProperties(
     // `implementation={my_trait(foo(bar))}` are not matched yet.
     if (!name)
       TODO(loc, "clause or extension trait matching in METADIRECTIVE");
-
-    llvm::omp::TraitProperty propKind =
-        llvm::omp::getOpenMPContextTraitPropertyKind(set, selector, name->v);
-    if (propKind != llvm::omp::TraitProperty::invalid) {
-      vmi.addTrait(set, propKind, name->v, scorePtr);
-      continue;
-    }
-
-    if (selector == llvm::omp::TraitSelector::device_isa) {
-      vmi.addTrait(set, llvm::omp::TraitProperty::device_isa___ANY, name->v,
-                   scorePtr);
-    } else if (selector == llvm::omp::TraitSelector::target_device_isa) {
-      vmi.addTrait(set, llvm::omp::TraitProperty::target_device_isa___ANY,
-                   name->v, scorePtr);
-    } else {
-      // For non-ISA selectors (arch, kind, vendor, etc.), unknown properties
-      // mean the variant cannot match. Add an invalid trait to ensure it is
-      // not selected.
-      vmi.addTrait(llvm::omp::TraitProperty::invalid, name->v, scorePtr);
-    }
   }
-}
-
-/// Try to constant-fold a user condition expression to a boolean.
-static std::optional<bool>
-evaluateUserCondition(semantics::SemanticsContext &semaCtx,
-                      const parser::ScalarExpr &scalarExpr) {
-  const auto *typedExpr = semantics::GetExpr(semaCtx, scalarExpr);
-  if (!typedExpr)
-    return std::nullopt;
-
-  auto foldedExpr = Fortran::evaluate::Fold(semaCtx.foldingContext(),
-                                            Fortran::common::Clone(*typedExpr));
-  if (auto constVal = Fortran::evaluate::ToInt64(foldedExpr))
-    return *constVal != 0;
-
-  if (auto logicalVal = Fortran::evaluate::GetScalarConstantValue<
-          Fortran::evaluate::LogicalResult>(foldedExpr))
-    return logicalVal->IsTrue();
-
-  return std::nullopt;
+  semantics::omp::ProcessTraitProperties(vmi, set, selector, props, scorePtr);
 }
 
 /// Process user={condition(...)} trait properties. Constant conditions are
@@ -1260,7 +1169,8 @@ static std::optional<DynamicUserCondition> processUserConditionTrait(
     if (!scalarExpr)
       continue;
 
-    if (auto constValue = evaluateUserCondition(semaCtx, *scalarExpr)) {
+    if (auto constValue =
+            semantics::omp::EvaluateUserCondition(semaCtx, *scalarExpr)) {
       vmi.addTrait(*constValue ? llvm::omp::TraitProperty::user_condition_true
                                : llvm::omp::TraitProperty::user_condition_false,
                    "<condition>", scorePtr);
@@ -1275,31 +1185,6 @@ static std::optional<DynamicUserCondition> processUserConditionTrait(
   return dynamicCond;
 }
 
-/// Extract the optional score value from trait properties.
-static llvm::APInt *
-getTraitScore(const std::optional<parser::OmpTraitSelector::Properties> &props,
-              semantics::SemanticsContext &semaCtx,
-              std::optional<llvm::APInt> &scoreStorage) {
-  if (!props)
-    return nullptr;
-
-  const auto &optScore =
-      std::get<std::optional<parser::OmpTraitScore>>(props->t);
-  if (!optScore)
-    return nullptr;
-
-  const auto *typedExpr = semantics::GetExpr(semaCtx, optScore->v);
-  if (!typedExpr)
-    return nullptr;
-
-  auto constVal = Fortran::evaluate::ToInt64(*typedExpr);
-  if (!constVal)
-    return nullptr;
-
-  scoreStorage = llvm::APInt(64, *constVal);
-  return &*scoreStorage;
-}
-
 /// Populate a VariantMatchInfo from context selector.
 /// For user conditions, attempts constant folding. Non-constant conditions
 /// are recorded as user_condition_unknown and returned for later use in
@@ -1313,13 +1198,14 @@ makeVariantMatchInfo(llvm::omp::VariantMatchInfo &vmi,
   for (const auto &traitSet : ctxSel.v) {
     using TSSName = parser::OmpTraitSetSelectorName;
     auto setName = std::get<TSSName>(traitSet.t).v;
-    llvm::omp::TraitSet set = mapTraitSet(setName);
+    llvm::omp::TraitSet set = semantics::omp::MapTraitSet(setName);
 
     for (const auto &trait :
          std::get<std::list<parser::OmpTraitSelector>>(traitSet.t)) {
       const auto &selectorName =
           std::get<parser::OmpTraitSelectorName>(trait.t);
-      llvm::omp::TraitSelector selector = mapTraitSelector(selectorName, set);
+      llvm::omp::TraitSelector selector =
+          semantics::omp::MapTraitSelector(selectorName, set);
       const auto &props =
           std::get<std::optional<parser::OmpTraitSelector::Properties>>(
               trait.t);
@@ -1330,7 +1216,8 @@ makeVariantMatchInfo(llvm::omp::VariantMatchInfo &vmi,
         TODO(loc, "target_device selector in METADIRECTIVE");
 
       std::optional<llvm::APInt> score;
-      llvm::APInt *scorePtr = getTraitScore(props, semaCtx, score);
+      llvm::APInt *scorePtr =
+          semantics::omp::GetTraitScore(props, semaCtx, score);
 
       if (selector == llvm::omp::TraitSelector::user_condition) {
         if (std::optional<DynamicUserCondition> userCond =

diff  --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 36fde727535d8..5fa653bd52951 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -230,16 +230,6 @@ std::optional<llvm::SmallVector<mlir::Value>> getIteratorElementIndices(
     Fortran::lower::AbstractConverter &converter, const omp::Object &object,
     Fortran::lower::StatementContext &stmtCtx, mlir::Location loc);
 
-/// Map a parsed OpenMP context trait-set selector to its OMPContext kind.
-llvm::omp::TraitSet
-mapTraitSet(parser::OmpTraitSetSelectorName::Value flangSet);
-
-/// Map a parsed OpenMP context trait selector within \p set to its OMPContext
-/// kind.
-llvm::omp::TraitSelector
-mapTraitSelector(const parser::OmpTraitSelectorName &name,
-                 llvm::omp::TraitSet set);
-
 /// Non-constant user condition expression and source for runtime lowering.
 struct DynamicUserCondition {
   const parser::ScalarExpr *expr;

diff  --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 51dd08d0924b1..633ec2ae45aaa 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -31,10 +31,12 @@
 #include "flang/Semantics/semantics.h"
 #include "flang/Semantics/symbol.h"
 
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Frontend/OpenMP/OMPContext.h"
 
 #include <array>
 #include <cinttypes>
@@ -1849,4 +1851,137 @@ WithReason<bool> LoopSequence::isRectangular(
 
   return result;
 }
+// ---------------------------------------------------------------------------
+// Trait-matching helpers shared between metadirective lowering and
+// declare-variant semantic recording.
+// ---------------------------------------------------------------------------
+
+llvm::omp::TraitSet MapTraitSet(parser::OmpTraitSetSelectorName::Value name) {
+  switch (name) {
+  case parser::OmpTraitSetSelectorName::Value::Construct:
+    return llvm::omp::TraitSet::construct;
+  case parser::OmpTraitSetSelectorName::Value::Device:
+    return llvm::omp::TraitSet::device;
+  case parser::OmpTraitSetSelectorName::Value::Implementation:
+    return llvm::omp::TraitSet::implementation;
+  case parser::OmpTraitSetSelectorName::Value::User:
+    return llvm::omp::TraitSet::user;
+  case parser::OmpTraitSetSelectorName::Value::Target_Device:
+    return llvm::omp::TraitSet::target_device;
+  }
+  llvm_unreachable("unknown trait set");
+}
+
+llvm::omp::TraitSelector MapTraitSelector(
+    const parser::OmpTraitSelectorName &name, llvm::omp::TraitSet set) {
+  if (const auto *val =
+          std::get_if<parser::OmpTraitSelectorName::Value>(&name.u)) {
+    switch (*val) {
+    case parser::OmpTraitSelectorName::Value::Kind:
+      if (set == llvm::omp::TraitSet::target_device)
+        return llvm::omp::TraitSelector::target_device_kind;
+      return llvm::omp::TraitSelector::device_kind;
+    case parser::OmpTraitSelectorName::Value::Arch:
+      if (set == llvm::omp::TraitSet::target_device)
+        return llvm::omp::TraitSelector::target_device_arch;
+      return llvm::omp::TraitSelector::device_arch;
+    case parser::OmpTraitSelectorName::Value::Isa:
+      if (set == llvm::omp::TraitSet::target_device)
+        return llvm::omp::TraitSelector::target_device_isa;
+      return llvm::omp::TraitSelector::device_isa;
+    case parser::OmpTraitSelectorName::Value::Vendor:
+      return llvm::omp::TraitSelector::implementation_vendor;
+    case parser::OmpTraitSelectorName::Value::Extension:
+      return llvm::omp::TraitSelector::implementation_extension;
+    case parser::OmpTraitSelectorName::Value::Condition:
+      return llvm::omp::TraitSelector::user_condition;
+    case parser::OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
+    case parser::OmpTraitSelectorName::Value::Requires:
+    case parser::OmpTraitSelectorName::Value::Simd:
+    case parser::OmpTraitSelectorName::Value::Device_Num:
+    case parser::OmpTraitSelectorName::Value::Uid:
+      break;
+    }
+  }
+  // Construct traits, extension strings, and remaining selectors use
+  // string-based lookup.
+  return llvm::omp::getOpenMPContextTraitSelectorKind(name.ToString(), set);
+}
+
+std::optional<bool> EvaluateUserCondition(
+    SemanticsContext &semaCtx, const parser::ScalarExpr &scalarExpr) {
+  const auto *typedExpr = GetExpr(semaCtx, scalarExpr);
+  if (!typedExpr)
+    return std::nullopt;
+
+  auto foldedExpr =
+      evaluate::Fold(semaCtx.foldingContext(), common::Clone(*typedExpr));
+  if (auto constVal = evaluate::ToInt64(foldedExpr))
+    return *constVal != 0;
+
+  if (auto logicalVal =
+          evaluate::GetScalarConstantValue<evaluate::LogicalResult>(foldedExpr))
+    return logicalVal->IsTrue();
+
+  return std::nullopt;
+}
+
+llvm::APInt *GetTraitScore(
+    const std::optional<parser::OmpTraitSelector::Properties> &props,
+    SemanticsContext &semaCtx, std::optional<llvm::APInt> &scoreStorage) {
+  if (!props)
+    return nullptr;
+
+  const auto &optScore =
+      std::get<std::optional<parser::OmpTraitScore>>(props->t);
+  if (!optScore)
+    return nullptr;
+
+  const auto *typedExpr = GetExpr(semaCtx, optScore->v);
+  if (!typedExpr)
+    return nullptr;
+
+  auto constVal = evaluate::ToInt64(*typedExpr);
+  if (!constVal)
+    return nullptr;
+
+  scoreStorage = llvm::APInt(64, *constVal);
+  return &*scoreStorage;
+}
+
+void ProcessTraitProperties(llvm::omp::VariantMatchInfo &vmi,
+    llvm::omp::TraitSet set, llvm::omp::TraitSelector selector,
+    const std::optional<parser::OmpTraitSelector::Properties> &props,
+    llvm::APInt *scorePtr) {
+  if (!props)
+    return;
+
+  for (const auto &prop :
+      std::get<std::list<parser::OmpTraitProperty>>(props->t)) {
+    const auto *name = std::get_if<parser::OmpTraitPropertyName>(&prop.u);
+    if (!name)
+      continue; // caller is responsible for diagnosing unsupported kinds
+
+    llvm::omp::TraitProperty propKind =
+        llvm::omp::getOpenMPContextTraitPropertyKind(set, selector, name->v);
+    if (propKind != llvm::omp::TraitProperty::invalid) {
+      vmi.addTrait(set, propKind, name->v, scorePtr);
+      continue;
+    }
+
+    if (selector == llvm::omp::TraitSelector::device_isa) {
+      vmi.addTrait(
+          set, llvm::omp::TraitProperty::device_isa___ANY, name->v, scorePtr);
+    } else if (selector == llvm::omp::TraitSelector::target_device_isa) {
+      vmi.addTrait(set, llvm::omp::TraitProperty::target_device_isa___ANY,
+          name->v, scorePtr);
+    } else {
+      // For non-ISA selectors (arch, kind, vendor, etc.), unknown properties
+      // mean the variant cannot match. Add an invalid trait to ensure it is
+      // not selected.
+      vmi.addTrait(llvm::omp::TraitProperty::invalid, name->v, scorePtr);
+    }
+  }
+}
+
 } // namespace Fortran::semantics::omp


        


More information about the flang-commits mailing list