[Openmp-commits] [openmp] 411a8ee - [libomp] Parse OMP_DEFAULT_DEVICE with new device trait parser (#176166)

via Openmp-commits openmp-commits at lists.llvm.org
Wed Sep 9 02:15:05 PDT 2026


Author: Robert Imschweiler
Date: 2026-09-09T11:15:00+02:00
New Revision: 411a8eea0c269fff79700da1b3a9e71914718d4b

URL: https://github.com/llvm/llvm-project/commit/411a8eea0c269fff79700da1b3a9e71914718d4b
DIFF: https://github.com/llvm/llvm-project/commit/411a8eea0c269fff79700da1b3a9e71914718d4b.diff

LOG: [libomp] Parse OMP_DEFAULT_DEVICE with new device trait parser (#176166)

... but do not yet expose the new functionalities to the user. This is a
backward compatible update that is going to be followed by the step to
the OpenMP 6.0 semantics as defined in 4.3.8.

Added: 
    

Modified: 
    openmp/runtime/src/i18n/en_US.txt
    openmp/runtime/src/kmp_settings.cpp
    openmp/runtime/src/kmp_traits.cpp
    openmp/runtime/src/kmp_traits.h
    openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp

Removed: 
    


################################################################################
diff  --git a/openmp/runtime/src/i18n/en_US.txt b/openmp/runtime/src/i18n/en_US.txt
index 3b7187edaeb13..84a515383a805 100644
--- a/openmp/runtime/src/i18n/en_US.txt
+++ b/openmp/runtime/src/i18n/en_US.txt
@@ -366,6 +366,9 @@ TraitParserError             "trait parser while parsing %1$s: error: %2$s"
 TraitParserInvalidTraitValue "trait parser while parsing %1$s: invalid value for trait '%2$s' (%3$s)"
 TraitParserMaxRecursion      "trait parser while parsing %1$s: max recursion depth (%2$d) exceeded"
 TraitParserFailed            "trait parser while parsing %1$s: failed to parse trait specification (%2$s)"
+TraitParserValueTooSmall     "trait parser while parsing %1$s: value %2$d below limit (%3$d)"
+TraitParserValueTooLarge     "trait parser while parsing %1$s: value %2$d above limit (%3$d)"
+TraitParserLegacyFailed      "legacy device number parser while parsing %1$s: failed to parse device number (%2$s)"
 
 # --- OpenMP errors detected at runtime ---
 #

diff  --git a/openmp/runtime/src/kmp_settings.cpp b/openmp/runtime/src/kmp_settings.cpp
index 8cd69099c9ca4..3ab604e15c017 100644
--- a/openmp/runtime/src/kmp_settings.cpp
+++ b/openmp/runtime/src/kmp_settings.cpp
@@ -23,6 +23,7 @@
 #include "kmp_lock.h"
 #include "kmp_settings.h"
 #include "kmp_str.h"
+#include "kmp_traits.h"
 #include "kmp_wrapper_getpid.h"
 #include <ctype.h> // toupper()
 #if OMPD_SUPPORT
@@ -1420,8 +1421,8 @@ static void __kmp_stg_print_max_active_levels(kmp_str_buf_t *buffer,
 // OpenMP 4.0: OMP_DEFAULT_DEVICE
 static void __kmp_stg_parse_default_device(char const *name, char const *value,
                                            void *data) {
-  __kmp_stg_parse_int(name, value, 0, KMP_MAX_DEFAULT_DEVICE_LIMIT,
-                      &__kmp_default_device);
+  __kmp_default_device = kmp_trait_context::parse_single_device(
+      value, /*device_num_min=*/0, KMP_MAX_DEFAULT_DEVICE_LIMIT, name);
 } // __kmp_stg_parse_default_device
 
 static void __kmp_stg_print_default_device(kmp_str_buf_t *buffer,

diff  --git a/openmp/runtime/src/kmp_traits.cpp b/openmp/runtime/src/kmp_traits.cpp
index 6070f388ec1d2..021dbbc90e3ad 100644
--- a/openmp/runtime/src/kmp_traits.cpp
+++ b/openmp/runtime/src/kmp_traits.cpp
@@ -421,3 +421,27 @@ kmp_trait_context *kmp_trait_context::parse_from_spec(kmp_str_ref spec,
   parser::consume_list(*context, lex, dbg_name);
   return context;
 }
+
+int kmp_trait_context::parse_single_device(kmp_str_ref spec, int device_num_min,
+                                           int device_num_max,
+                                           const char *dbg_name) {
+  int device_num;
+  kmp_str_ref orig_spec = spec;
+
+  spec.skip_space();
+  if (!spec.consume_integer(device_num, /*allow_zero=*/true,
+                            /*allow_negative=*/true))
+    KMP_FATAL(TraitParserLegacyFailed, dbg_name, orig_spec.copy());
+  spec.skip_space();
+  if (!spec.empty())
+    KMP_FATAL(TraitParserLegacyFailed, dbg_name, orig_spec.copy());
+
+  if (device_num < device_num_min) {
+    KMP_WARNING(TraitParserValueTooSmall, dbg_name, device_num, device_num_min);
+    device_num = device_num_min;
+  } else if (device_num > device_num_max) {
+    KMP_WARNING(TraitParserValueTooLarge, dbg_name, device_num, device_num_max);
+    device_num = device_num_max;
+  }
+  return device_num;
+}

diff  --git a/openmp/runtime/src/kmp_traits.h b/openmp/runtime/src/kmp_traits.h
index 66913bd9db22c..796e9fc771938 100644
--- a/openmp/runtime/src/kmp_traits.h
+++ b/openmp/runtime/src/kmp_traits.h
@@ -438,6 +438,14 @@ class kmp_trait_context final {
   static kmp_trait_context *parse_from_spec(kmp_str_ref spec,
                                             const char *dbg_name = nullptr);
 
+  // Parse only a single device number from the spec.
+  // This is useful for backward compatibility with legacy code.
+  // If dbg_name is provided, it will be used in error messages to identify the
+  // source of the device number.
+  static int parse_single_device(kmp_str_ref spec, int device_num_min,
+                                 int device_num_max,
+                                 const char *dbg_name = nullptr);
+
   void add_clause(kmp_trait_clause *clause) {
     assert(clause);
     clauses.push_back(clause);

diff  --git a/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp b/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp
index 59e2c4b07318a..633468bf28f37 100644
--- a/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp
+++ b/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp
@@ -1069,4 +1069,109 @@ TEST_F(ParserTest, MaxRecursionExceeded) {
                "max recursion depth \\(64\\) exceeded");
 }
 
+//===----------------------------------------------------------------------===//
+// parse_single_device Tests
+//===----------------------------------------------------------------------===//
+
+TEST(ParseSingleDeviceTest, ValidSingleDigit) {
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("5"), 0, 10);
+  EXPECT_EQ(result, 5);
+}
+
+TEST(ParseSingleDeviceTest, ValidMultiDigit) {
+  int result =
+      kmp_trait_context::parse_single_device(kmp_str_ref("123"), 0, 200);
+  EXPECT_EQ(result, 123);
+}
+
+TEST(ParseSingleDeviceTest, Zero) {
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("0"), 0, 10);
+  EXPECT_EQ(result, 0);
+}
+
+TEST(ParseSingleDeviceTest, AtMax) {
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("10"), 0, 10);
+  EXPECT_EQ(result, 10);
+}
+
+TEST(ParseSingleDeviceTest, AtMin) {
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("2"), 2, 10);
+  EXPECT_EQ(result, 2);
+}
+
+TEST(ParseSingleDeviceTest, AboveMaxClampsToMax) {
+  // Values above the maximum are warned about and clamped to the maximum.
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("11"), 0, 10);
+  EXPECT_EQ(result, 10);
+}
+
+TEST(ParseSingleDeviceTest, BelowMinClampsToMin) {
+  // Values below the minimum are warned about and clamped to the minimum.
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("2"), 5, 10);
+  EXPECT_EQ(result, 5);
+}
+
+TEST(ParseSingleDeviceTest, NegativeValue) {
+  // Negative device numbers are allowed within range.
+  int result =
+      kmp_trait_context::parse_single_device(kmp_str_ref("-1"), -5, 10);
+  EXPECT_EQ(result, -1);
+}
+
+TEST(ParseSingleDeviceTest, NegativeBelowMinClampsToMin) {
+  // Negative values below the minimum are clamped to the minimum.
+  int result = kmp_trait_context::parse_single_device(kmp_str_ref("-7"), 0, 10);
+  EXPECT_EQ(result, 0);
+}
+
+TEST(ParseSingleDeviceTest, NonInteger) {
+  ASSERT_DEATH(kmp_trait_context::parse_single_device(kmp_str_ref("abc"), 0, 10,
+                                                      "non_integer"),
+               "OMP: Error #[0-9]+: legacy device number parser while parsing "
+               "non_integer: failed to parse device number \\(abc\\)");
+}
+
+TEST(ParseSingleDeviceTest, EmptyString) {
+  ASSERT_DEATH(
+      kmp_trait_context::parse_single_device(kmp_str_ref(""), 0, 10, "empty"),
+      "OMP: Error #[0-9]+: legacy device number parser while parsing empty: "
+      "failed to parse device number \\(\\)");
+}
+
+TEST(ParseSingleDeviceTest, LeadingSpaces) {
+  // consume_integer skips leading spaces
+  int result =
+      kmp_trait_context::parse_single_device(kmp_str_ref("  7"), 0, 10);
+  EXPECT_EQ(result, 7);
+}
+
+TEST(ParseSingleDeviceTest, LargeNumber) {
+  int result =
+      kmp_trait_context::parse_single_device(kmp_str_ref("999999"), 0, 1000000);
+  EXPECT_EQ(result, 999999);
+}
+
+TEST(ParseSingleDeviceTest, TrailingGarbage) {
+  // Trailing non-integer characters must not be silently ignored.
+  ASSERT_DEATH(kmp_trait_context::parse_single_device(kmp_str_ref("10abc"), 0,
+                                                      100, "trailing_garbage"),
+               "OMP: Error #[0-9]+: legacy device number parser while parsing "
+               "trailing_garbage: failed to parse device number \\(10abc\\)");
+}
+
+TEST(ParseSingleDeviceTest, TrailingList) {
+  // Only a single device is accepted; a comma-separated list must fail.
+  ASSERT_DEATH(kmp_trait_context::parse_single_device(kmp_str_ref("10,11"), 0,
+                                                      100, "trailing_list"),
+               "OMP: Error #[0-9]+: legacy device number parser while parsing "
+               "trailing_list: failed to parse device number \\(10,11\\)");
+}
+
+TEST(ParseSingleDeviceTest, TrailingSpaces) {
+  // Trailing whitespace is allowed.
+  int result =
+      kmp_trait_context::parse_single_device(kmp_str_ref("7  "), 0, 10);
+  EXPECT_EQ(result, 7);
+}
+
 } // namespace


        


More information about the Openmp-commits mailing list