[llvm-branch-commits] [openmp] [libomp] Parse OMP_DEFAULT_DEVICE with new device trait parser (PR #176166)
Robert Imschweiler via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jun 18 05:14:57 PDT 2026
https://github.com/ro-i updated https://github.com/llvm/llvm-project/pull/176166
>From 60416cf8f54ee83b4d7b369043970d6e8ec5aa74 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Thu, 15 Jan 2026 06:49:10 -0600
Subject: [PATCH] [libomp] Parse OMP_DEFAULT_DEVICE with new device trait
parser
... 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.
---
openmp/runtime/src/i18n/en_US.txt | 3 +
openmp/runtime/src/kmp_settings.cpp | 5 +-
openmp/runtime/src/kmp_traits.cpp | 24 ++++
openmp/runtime/src/kmp_traits.h | 8 ++
.../unittests/Traits/TestOMPTraitParser.cpp | 105 ++++++++++++++++++
5 files changed, 143 insertions(+), 2 deletions(-)
diff --git a/openmp/runtime/src/i18n/en_US.txt b/openmp/runtime/src/i18n/en_US.txt
index f45b2e70d1547..00ab391944292 100644
--- a/openmp/runtime/src/i18n/en_US.txt
+++ b/openmp/runtime/src/i18n/en_US.txt
@@ -365,6 +365,9 @@ TopologyHybridCoreEff "%1$s: %2$d with core efficiency %3$d."
TraitParserInvalidUID "trait parser while parsing %1$s: invalid uid (%2$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 66ef6f8097dce..34ccc0f096f01 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
@@ -1415,8 +1416,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 ad307833c6aac..f60c9c7fc81c4 100644
--- a/openmp/runtime/src/kmp_traits.cpp
+++ b/openmp/runtime/src/kmp_traits.cpp
@@ -292,3 +292,27 @@ kmp_trait_context *kmp_trait_context::parse_from_spec(kmp_str_ref spec,
KMP_FATAL(TraitParserFailed, dbg_name, spec.copy());
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 052017a66225f..e3e881ae09797 100644
--- a/openmp/runtime/src/kmp_traits.h
+++ b/openmp/runtime/src/kmp_traits.h
@@ -361,6 +361,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 08f19ad72e322..536ce3caf3f6c 100644
--- a/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp
+++ b/openmp/runtime/unittests/Traits/TestOMPTraitParser.cpp
@@ -978,4 +978,109 @@ TEST_F(ParserTest, DoubleComma) {
"failed to parse trait specification \\(,,uid\\(b\\)\\)");
}
+//===----------------------------------------------------------------------===//
+// 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 llvm-branch-commits
mailing list