[Openmp-commits] [openmp] [libomp] OpenMP 6.0: Add device trait parser (PR #176164)
Krzysztof Parzyszek via Openmp-commits
openmp-commits at lists.llvm.org
Sun Jul 5 16:12:13 PDT 2026
================
@@ -0,0 +1,294 @@
+/*
+ * kmp_traits.cpp -- Handle OpenMP context traits
+ *
+ * OpenMP 6.0 specifies the following trait sets:
+ * - construct
+ * - device
+ * - target device
+ * - implementation
+ * - extension
+ * - dynamic
+ * Currently, the implementation in this file supports traits from the (target)
+ * device and implementation trait sets that are relevant for implementing the
+ * OMP_DEFAULT_DEVICE and OMP_AVAILABLE_DEVICES environment variables.
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "kmp_traits.h"
+#include "kmp_i18n.h"
+
+using namespace kmp_traits;
+
+// OpenMP trait grammar (in EBNF), currently used for parsing the
+// OMP_DEFAULT_DEVICE/OMP_AVAILABLE_DEVICES environment variables
+//
+// Notes about the grammar:
+// - Device traits are going to be translated into device numbers (aka integers)
+// later in the runtime. The parser handles device numbers as device traits that
+// have already been translated.
+// - "*" is also not a trait, strictly speaking. But it's also supported by the
+// parser and converted into a "match any" wildcard trait.
+// - OpenMP 6.0 explicitly excludes "&&" and "||" from appearing in the same
+// grouping level.
+// - This grammar currently only supports plain integers for array subsripts /
+// sections, no expressions.
+// - TODO:
+// - Add support for more traits
+//
+// TODOs regarding the implementation (not the grammar):
+// - Implement array subscript/section parsing
+// - Implement grammar TODOs after they have been incorporated into the grammar
+//
+// list = [clause {',' clause}]
+// clause =
+// device_number
+// | "*" [index_expr]
+// | trait_expr_group
+// | trait_expr index_expr
+// device_number = ["-"] integer0
+// trait_expr_group =
+// trait_expr
+// | trait_expr {"&&" trait_expr}
+// | trait_expr {"||" trait_expr}
+// trait_expr =
+// trait_expr_single
+// | trait_expr_group_paren
+// trait_expr_single = ["!"] trait
+// trait_expr_group_paren = ["!"] "(" trait_expr_group ")"
+// trait =
+// "uid" "(" uid_value ")"
+// uid_value = (letter | digit0 | symbol) {letter | digit0 | symbol}
+//
+// index_expr = "[" integer0 "]" | "[" array_section "]"
+// array_section =
+// lower_bound ":" length ":" stride
+// | lower_bound ":" length ":"
+// | lower_bound ":" length
+// | lower_bound "::" stride
+// | lower_bound "::"
+// | lower_bound ":"
+// | ":" length ":" stride
+// | ":" length ":"
+// | ":" length
+// | "::" stride
+// | "::"
+// | ":"
+// lower_bound = integer0
+// length = integer0
+// stride = integer
+//
+// integer0 = 0 | integer
+// integer = digit {digit0}
+//
+// letter =
+// "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L"
+// | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X"
+// | "Y" | "Z" | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
+// | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v"
+// | "w" | "x" | "y" | "z"
+// digit0 = "0" | digit
+// digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+// symbol = "-" | "_"
+
+namespace parser {
+
+#define MAX_RECURSION_DEPTH 64
+
+using namespace kmp_traits;
+
+static kmp_str_ref consume_uid_value(kmp_str_ref &scan, const char *dbg_name) {
+ scan.skip_space();
+ kmp_str_ref uid = scan.take_while([](char c) {
+ return isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_';
+ });
+ scan.drop_front(uid.length());
+ if (uid.empty() || !scan.consume_front(")"))
+ KMP_FATAL(TraitParserInvalidUID, dbg_name, uid.copy());
+ return uid;
+}
+
+static bool consume_trait(kmp_trait_expr_single &expr, kmp_str_ref &scan,
+ const char *dbg_name) {
+ scan.skip_space();
+ if (!scan.consume_front("uid("))
+ return false;
+ kmp_str_ref uid = consume_uid_value(scan, dbg_name);
+ expr.set_trait(new kmp_uid_trait(uid));
+ return true;
+}
+
+static bool consume_trait_expr_single(kmp_trait_expr_single &expr,
+ kmp_str_ref &scan, const char *dbg_name) {
+ kmp_str_ref orig_scan = scan;
+
+ scan.skip_space();
+ if (scan.consume_front("!"))
+ expr.set_negated();
+ if (consume_trait(expr, scan, dbg_name))
+ return true;
+ scan = orig_scan;
+ return false;
+}
+
+// forward declaration
+static bool consume_trait_expr_group(kmp_trait_expr_group &group,
+ kmp_str_ref &scan, int max_recursion,
+ const char *dbg_name);
+
+static bool consume_trait_expr_group_paren(kmp_trait_expr_group &group,
+ kmp_str_ref &scan, int max_recursion,
+ const char *dbg_name) {
+ if (max_recursion-- <= 0)
+ KMP_FATAL(TraitParserMaxRecursion, dbg_name, MAX_RECURSION_DEPTH);
+ kmp_str_ref orig_scan = scan;
+
+ scan.skip_space();
+ if (scan.consume_front("!"))
+ group.set_negated();
+
+ scan.skip_space();
+ if (!scan.consume_front("(") ||
+ !consume_trait_expr_group(group, scan, max_recursion, dbg_name)) {
+ scan = orig_scan;
+ return false;
+ }
+
+ scan.skip_space();
+ if (!scan.consume_front(")")) {
+ scan = orig_scan;
+ return false;
+ }
+ return true;
+}
+
+static bool consume_trait_expr(kmp_trait_expr *&expr, kmp_str_ref &scan,
+ int max_recursion, const char *dbg_name) {
+ if (max_recursion-- <= 0)
+ KMP_FATAL(TraitParserMaxRecursion, dbg_name, MAX_RECURSION_DEPTH);
+
+ // Parse a single trait expression
+ kmp_trait_expr_single *single_expr = new kmp_trait_expr_single();
+ if (consume_trait_expr_single(*single_expr, scan, dbg_name)) {
+ expr = single_expr;
+ return true;
+ }
+ delete single_expr;
----------------
kparzysz wrote:
This looks like an anti-pattern.
https://github.com/llvm/llvm-project/pull/176164
More information about the Openmp-commits
mailing list