[llvm-branch-commits] [flang] [llvm] [OpenMP][flang] Score unknown context selector properties by selector (PR #232960)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Oct 16 14:56:02 PDT 2026


https://github.com/chichunchen created https://github.com/llvm/llvm-project/pull/232960

Flang records an unknown property such as kind(bogus) or vendor(bogus) as TraitProperty::invalid, which belongs to no selector. Under match_any or match_none, where such a variant can still be selected, the property therefore lost its selector's weight: kind(bogus) added nothing, while an unmatched kind(gpu) adds 2^l. A score on a selector that mixes known and unknown properties was also added twice, once for the known property and once for invalid, and unknown properties in different selectors shared a single score.

Add VariantMatchInfo::addUnknownTrait, which keeps the property unmatched and records its selector and score, and score that selector like any other. Use it in Flang. Clang drops unknown properties while parsing and is unaffected.

Assisted-by: GitHub Copilot (Claude Opus 5.5)

>From 709035d67ce871b7bafd079c5181dc60629d88c2 Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Fri, 16 Oct 2026 16:35:09 -0500
Subject: [PATCH] [OpenMP][flang] Score unknown context selector properties by
 selector

Flang records an unknown property such as kind(bogus) or vendor(bogus)
as TraitProperty::invalid, which belongs to no selector. Under
match_any or match_none, where such a variant can still be selected,
the property therefore lost its selector's weight: kind(bogus) added
nothing, while an unmatched kind(gpu) adds 2^l. A score on a selector
that mixes known and unknown properties was also added twice, once for
the known property and once for invalid, and unknown properties in
different selectors shared a single score.

Add VariantMatchInfo::addUnknownTrait, which keeps the property
unmatched and records its selector and score, and score that selector
like any other. Use it in Flang. Clang drops unknown properties while
parsing and is unaffected.

Assisted-by: GitHub Copilot (Claude Opus 5.5)
---
 flang/lib/Semantics/openmp-utils.cpp          |  6 +--
 .../OpenMP/metadirective-implementation.f90   | 30 ++++++++++++++
 .../include/llvm/Frontend/OpenMP/OMPContext.h | 15 +++++++
 llvm/lib/Frontend/OpenMP/OMPContext.cpp       |  8 +++-
 llvm/unittests/Frontend/OpenMPContextTest.cpp | 39 ++++++++++++++++++-
 5 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 16c265ce39690d..54ac0521e6a5b2 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -2410,10 +2410,8 @@ void ProcessTraitProperties(llvm::omp::VariantMatchInfo &vmi,
       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);
+      // An unknown property never matches, but its selector is still scored.
+      vmi.addUnknownTrait(selector, scorePtr);
     }
   }
 }
diff --git a/flang/test/Lower/OpenMP/metadirective-implementation.f90 b/flang/test/Lower/OpenMP/metadirective-implementation.f90
index cd61b733cbb1d3..9f829ebae5a0a0 100644
--- a/flang/test/Lower/OpenMP/metadirective-implementation.f90
+++ b/flang/test/Lower/OpenMP/metadirective-implementation.f90
@@ -17,6 +17,36 @@ subroutine test_unknown_vendor_match_none()
   !$omp& when(user={condition(.true.)}: barrier)
 end subroutine
 
+! An unknown KIND property weighs like an unmatched known one: inside PARALLEL,
+! KIND adds 2 and beats the vendor score of 1.
+! CHECK-LABEL: func.func @_QPtest_unknown_kind_weight()
+! CHECK: omp.parallel
+! CHECK-NOT: omp.barrier
+! CHECK: omp.taskyield
+! CHECK-NOT: omp.barrier
+! CHECK: omp.terminator
+subroutine test_unknown_kind_weight()
+  !$omp parallel
+  !$omp metadirective &
+  !$omp& when(device={kind(bogus_kind)}, implementation={extension(match_none)}: &
+  !$omp& taskyield) &
+  !$omp& when(implementation={vendor(score(1): llvm)}: barrier)
+  !$omp end parallel
+end subroutine
+
+! A score on a selector with a known and an unknown property counts once:
+! 1 + 5 loses to 1 + 8.
+! CHECK-LABEL: func.func @_QPtest_mixed_vendor_score()
+! CHECK-NOT: omp.taskyield
+! CHECK: omp.barrier
+! CHECK-NEXT: return
+subroutine test_mixed_vendor_score()
+  !$omp metadirective &
+  !$omp& when(implementation={vendor(score(5): llvm, bogus_vendor), &
+  !$omp& extension(match_any)}: taskyield) &
+  !$omp& when(user={condition(score(8): .true.)}: barrier)
+end subroutine
+
 ! CHECK-LABEL: func.func @_QPtest_vendor_llvm()
 ! CHECK:         omp.taskwait
 ! CHECK:         return
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
index 7849d326659944..29f58667ba6ce9 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
 #include "llvm/Support/Compiler.h"
+#include <optional>
 
 namespace llvm {
 class Triple;
@@ -122,6 +123,11 @@ LLVM_ABI bool isValidTraitPropertyForTraitSetAndSelector(TraitProperty Property,
 /// scored (via the ScoresMap). In addition, the required consturct nesting is
 /// decribed as well.
 struct VariantMatchInfo {
+  struct UnknownTrait {
+    TraitSelector Selector;
+    std::optional<APInt> Score;
+  };
+
   /// Add the trait \p Property to the required trait set. \p RawString is the
   /// string we parsed and derived \p Property from. If \p Score is not null, it
   /// recorded as well. If \p Property is in the `construct` set it is recorded
@@ -152,10 +158,19 @@ struct VariantMatchInfo {
       ConstructTraits.push_back(Property);
   }
 
+  /// Add an unknown property of \p Selector. It never matches, but its
+  /// selector is scored like a known property's.
+  void addUnknownTrait(TraitSelector Selector, APInt *Score = nullptr) {
+    UnknownTraits.push_back(
+        {Selector, Score ? std::optional<APInt>(*Score) : std::nullopt});
+    RequiredTraits.set(unsigned(TraitProperty::invalid));
+  }
+
   BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1);
   SmallVector<StringRef, 8> ISATraits;
   SmallVector<TraitProperty, 8> ConstructTraits;
   SmallDenseMap<TraitProperty, APInt> ScoreMap;
+  SmallVector<UnknownTrait, 2> UnknownTraits;
 };
 
 /// The context for a source location is made up of active property traits,
diff --git a/llvm/lib/Frontend/OpenMP/OMPContext.cpp b/llvm/lib/Frontend/OpenMP/OMPContext.cpp
index ab7104b58aed82..be30b2dcbb56ff 100644
--- a/llvm/lib/Frontend/OpenMP/OMPContext.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp
@@ -375,9 +375,11 @@ static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
   };
   for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
     TraitProperty Property = TraitProperty(Bit);
-    // Construct scores use ordered positions below. kind(any) is treated as
-    // if no kind selector were specified.
+    // Construct scores use ordered positions below, and unknown properties
+    // their UnknownTraits entries. kind(any) is treated as if no kind selector
+    // were specified.
     if (getOpenMPContextTraitSetForProperty(Property) == TraitSet::construct ||
+        Property == TraitProperty::invalid ||
         Property == TraitProperty::device_kind_any ||
         Property == TraitProperty::target_device_kind_any)
       continue;
@@ -385,6 +387,8 @@ static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
     AddSelectorScore(getOpenMPContextTraitSelectorForProperty(Property),
                      It == VMI.ScoreMap.end() ? nullptr : &It->second);
   }
+  for (const VariantMatchInfo::UnknownTrait &Trait : VMI.UnknownTraits)
+    AddSelectorScore(Trait.Selector, Trait.Score ? &*Trait.Score : nullptr);
 
   assert(VMI.ConstructTraits.size() >= ConstructMatches.size() &&
          "Mismatch in the construct traits!");
diff --git a/llvm/unittests/Frontend/OpenMPContextTest.cpp b/llvm/unittests/Frontend/OpenMPContextTest.cpp
index cc600a0a892e0b..f6e4ca25169559 100644
--- a/llvm/unittests/Frontend/OpenMPContextTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPContextTest.cpp
@@ -385,7 +385,7 @@ TEST_F(OpenMPContextTest, ScoringMatchAnyWithoutMatchingConstructs) {
 TEST_F(OpenMPContextTest, ScoringInvalidProperty) {
   OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
   VariantMatchInfo Unknown;
-  Unknown.addTrait(TraitProperty::invalid, "bogus_vendor");
+  Unknown.addUnknownTrait(TraitSelector::implementation_vendor);
   EXPECT_FALSE(isVariantApplicableInContext(Unknown, Context));
   Unknown.addTrait(TraitProperty::implementation_extension_match_none, "");
   EXPECT_TRUE(isVariantApplicableInContext(Unknown, Context));
@@ -400,6 +400,35 @@ TEST_F(OpenMPContextTest, ScoringInvalidProperty) {
   APInt Score(64, 1);
   Candidates[1].addTrait(TraitProperty::user_condition_true, "", &Score);
   EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
+
+  // A selector with only unknown properties keeps its score: 1 + 2 beats 1 + 1.
+  APInt UnknownScore(64, 2);
+  Candidates[0] = VariantMatchInfo();
+  Candidates[0].addUnknownTrait(TraitSelector::implementation_vendor,
+                                &UnknownScore);
+  Candidates[0].addTrait(TraitProperty::implementation_extension_match_none,
+                         "");
+  EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
+}
+
+TEST_F(OpenMPContextTest, ScoringUnknownDeviceProperties) {
+  OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
+  Context.addTrait(TraitProperty::construct_parallel_parallel);
+  // With one enclosing construct, kind is worth 2 and arch 4, matched or not.
+  for (auto [Selector, Weight] : {std::pair(TraitSelector::device_kind, 2u),
+                                  std::pair(TraitSelector::device_arch, 4u)}) {
+    SCOPED_TRACE(unsigned(Selector));
+    VariantMatchInfo Unknown, Scored;
+    Unknown.addUnknownTrait(Selector);
+    Unknown.addTrait(TraitProperty::implementation_extension_match_none, "");
+    APInt Score(64, Weight - 1);
+    Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
+    SmallVector<VariantMatchInfo, 2> Candidates{Scored, Unknown};
+    EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
+    Score = APInt(64, Weight);
+    Candidates[0].addTrait(TraitProperty::user_condition_true, "", &Score);
+    EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
+  }
 }
 
 TEST_F(OpenMPContextTest, ScoringUserScoreOncePerSelector) {
@@ -416,6 +445,14 @@ TEST_F(OpenMPContextTest, ScoringUserScoreOncePerSelector) {
   // The vendor score counts once: 1 + 10 loses to 1 + 11.
   SmallVector<VariantMatchInfo, 2> Candidates{TwoVendors, Scored};
   EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
+
+  // The same holds when one of the vendors is unknown.
+  VariantMatchInfo Mixed;
+  Mixed.addTrait(TraitProperty::implementation_vendor_llvm, "", &VendorScore);
+  Mixed.addUnknownTrait(TraitSelector::implementation_vendor, &VendorScore);
+  Mixed.addTrait(TraitProperty::implementation_extension_match_any, "");
+  Candidates[0] = Mixed;
+  EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
 }
 
 TEST_F(OpenMPContextTest, ScoringMultipleProperties) {



More information about the llvm-branch-commits mailing list