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 <[email protected]> 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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
