[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