13#ifndef OPENMP_TRAITS_H
14#define OPENMP_TRAITS_H
23enum class token_kind {
42 token_kind kind = token_kind::UNKNOWN;
43 kmp_str_ref text = kmp_str_ref(
"");
46class kmp_lexer final {
48 token lookahead{token_kind::END, kmp_str_ref(
"")};
49 bool has_lookahead =
false;
55 explicit kmp_lexer(kmp_str_ref source) : scan(source) {}
60 has_lookahead =
false;
77 kmp_str_ref remaining() {
79 return kmp_str_ref(t.text.begin(),
80 static_cast<size_t>(scan.end() - t.text.begin()));
88extern "C" int omp_get_num_devices();
89extern "C" const char *omp_get_uid_from_device(
int device_num);
93 enum trait_type { WILDCARD_T, LITERAL_T, UID_T };
96 kmp_trait(trait_type type) : _type(type) {}
99 virtual ~kmp_trait() =
default;
101 kmp_trait(
const kmp_trait &) =
delete;
102 kmp_trait(kmp_trait &&) =
delete;
103 kmp_trait &operator=(
const kmp_trait &) =
delete;
104 kmp_trait &operator=(kmp_trait &&) =
delete;
108 virtual bool match([[maybe_unused]]
int device)
const {
109 KMP_ASSERT2(0,
"kmp_trait::match() must be overridden");
114 void *
operator new(
size_t size) {
return KMP_INTERNAL_MALLOC(size); }
115 void operator delete(
void *ptr) { KMP_INTERNAL_FREE(ptr); }
117 virtual bool operator==(
const kmp_trait &other)
const {
118 return _type == other._type;
123class kmp_wildcard_trait final :
public kmp_trait {
125 kmp_wildcard_trait() : kmp_trait(WILDCARD_T) {}
127 bool match([[maybe_unused]]
int device)
const override {
return true; }
129 bool operator==(
const kmp_trait &other)
const override {
130 return kmp_trait::operator==(other);
135class kmp_literal_trait final :
public kmp_trait {
139 kmp_literal_trait(
int device_num)
140 : kmp_trait(LITERAL_T), device_num(device_num) {
141 assert(device_num >= 0 &&
"Device number must be non-negative");
144 bool match(
int device)
const override {
return device_num == device; }
146 bool operator==(
const kmp_trait &other)
const override {
147 return kmp_trait::operator==(other) &&
149 static_cast<const kmp_literal_trait &
>(other).device_num;
158class kmp_uid_trait final :
public kmp_trait {
161 const char *(*get_uid_from_device)(
int device) = omp_get_uid_from_device;
164 kmp_uid_trait(
kmp_str_ref uid) : kmp_trait(UID_T), uid(uid.copy()) {}
166 ~kmp_uid_trait()
override {
168 KMP_INTERNAL_FREE(uid);
171 bool match(
int device)
const override {
172 const char *device_uid = get_uid_from_device(device);
173 if (!device_uid || !uid)
175 return strcmp(device_uid, uid) == 0;
180 void set_uid_from_device(
const char *(*uid_from_device)(
int)) {
181 get_uid_from_device = uid_from_device;
184 bool operator==(
const kmp_trait &other)
const override {
185 if (!kmp_trait::operator==(other))
187 const char *other_uid =
static_cast<const kmp_uid_trait &
>(other).uid;
188 return uid && other_uid ? strcmp(uid, other_uid) == 0 : uid == other_uid;
194class kmp_trait_expr {
196 enum expr_type { SINGLE_T, GROUP_T };
199 bool negated =
false;
201 int (*get_num_devices)() = omp_get_num_devices;
203 kmp_trait_expr(expr_type type) : _type(type) {}
204 kmp_trait_expr(expr_type type,
bool negated)
205 : _type(type), negated(negated) {}
209 virtual bool match_impl([[maybe_unused]]
int device,
210 [[maybe_unused]]
int num_devices)
const {
211 KMP_ASSERT2(0,
"kmp_trait_expr::match_impl() must be overridden");
216 virtual ~kmp_trait_expr() =
default;
218 kmp_trait_expr(
const kmp_trait_expr &) =
delete;
219 kmp_trait_expr(kmp_trait_expr &&) =
delete;
220 kmp_trait_expr &operator=(
const kmp_trait_expr &) =
delete;
221 kmp_trait_expr &operator=(kmp_trait_expr &&) =
delete;
223 bool is_negated()
const {
return negated; }
226 bool match(
int device,
int num_devices = -1)
const {
227 if (num_devices == -1)
228 num_devices = get_num_devices();
229 if (device < 0 || device >= num_devices)
231 return match_impl(device, num_devices);
234 void set_negated(
bool neg =
true) { negated = neg; }
238 void set_num_devices(
int (*num_devices)()) { get_num_devices = num_devices; }
241 void *
operator new(
size_t size) {
return KMP_INTERNAL_MALLOC(size); }
242 void operator delete(
void *ptr) { KMP_INTERNAL_FREE(ptr); }
244 virtual bool operator==(
const kmp_trait_expr &other)
const {
245 return _type == other._type && negated == other.negated;
250class kmp_trait_expr_single final :
public kmp_trait_expr {
251 kmp_trait *trait =
nullptr;
254 bool match_impl(
int device, [[maybe_unused]]
int num_devices)
const override {
256 bool result = trait->match(device);
257 return negated ? !result : result;
261 kmp_trait_expr_single() : kmp_trait_expr(SINGLE_T) {}
262 kmp_trait_expr_single(
bool negated) : kmp_trait_expr(SINGLE_T, negated) {}
263 kmp_trait_expr_single(kmp_trait *trait)
264 : kmp_trait_expr(SINGLE_T), trait(trait) {
265 assert(trait &&
"kmp_trait_expr_single requires a non-null trait");
267 ~kmp_trait_expr_single()
override {
delete trait; }
269 void set_trait(kmp_trait *new_trait) {
276 bool operator==(
const kmp_trait_expr &other)
const override {
277 if (!kmp_trait_expr::operator==(other))
279 const kmp_trait_expr_single &other_single =
280 static_cast<const kmp_trait_expr_single &
>(other);
281 return trait && other_single.trait ? *trait == *other_single.trait
282 : trait == other_single.trait;
288class kmp_trait_expr_group final :
public kmp_trait_expr {
290 enum group_type { AND, OR };
295 group_type type = OR;
298 bool match_impl(
int device,
int num_devices)
const override {
300 for (
const kmp_trait_expr *expr : exprs) {
301 if (expr->match(device, num_devices))
305 bool result = type == AND ? matched == exprs.size() : matched > 0;
306 return negated ? !result : result;
310 kmp_trait_expr_group() : kmp_trait_expr(GROUP_T) {}
311 kmp_trait_expr_group(
bool negated) : kmp_trait_expr(GROUP_T, negated) {}
312 ~kmp_trait_expr_group()
override {
313 for (kmp_trait_expr *expr : exprs)
317 void add_expr(kmp_trait *trait) {
321 void add_expr(kmp_trait_expr *expr) {
323 exprs.push_back(expr);
325 expr->set_num_devices(get_num_devices);
328 group_type get_group_type()
const {
return type; }
330 void set_group_type(group_type new_type) { type = new_type; }
332 void set_num_devices(
int (*num_devices)()) {
333 kmp_trait_expr::set_num_devices(num_devices);
334 for (kmp_trait_expr *expr : exprs)
335 expr->set_num_devices(num_devices);
338 bool operator==(
const kmp_trait_expr &other)
const override {
339 if (!kmp_trait_expr::operator==(other))
341 const kmp_trait_expr_group &other_group =
342 static_cast<const kmp_trait_expr_group &
>(other);
343 return type == other_group.type &&
344 exprs.is_set_equal(other_group.exprs,
345 [](
const kmp_trait_expr *a,
346 const kmp_trait_expr *b) { return *a == *b; });
350class kmp_trait_clause final {
354 kmp_trait_clause() =
default;
355 ~kmp_trait_clause() {
delete expr; }
357 kmp_trait_clause(
const kmp_trait_clause &) =
delete;
358 kmp_trait_clause(kmp_trait_clause &&) =
delete;
359 kmp_trait_clause &operator=(
const kmp_trait_clause &) =
delete;
360 kmp_trait_clause &operator=(kmp_trait_clause &&) =
delete;
362 kmp_trait_expr *get_expr() {
return expr; }
364 bool match(
int device,
int num_devices = -1)
const {
366 return expr->match(device, num_devices);
369 void set_expr(kmp_trait *trait) {
373 expr =
new kmp_trait_expr_single(trait);
375 void set_expr(kmp_trait_expr *new_expr) {
383 void *
operator new(
size_t size) {
return KMP_INTERNAL_MALLOC(size); }
384 void operator delete(
void *ptr) { KMP_INTERNAL_FREE(ptr); }
386 bool operator==(
const kmp_trait_clause &other)
const {
387 return expr && other.expr ? *expr == *other.expr : expr == other.expr;
393class kmp_trait_context final {
394 using kmp_trait_clause = kmp_traits::kmp_trait_clause;
395 using kmp_trait_expr = kmp_traits::kmp_trait_expr;
397 kmp_vector<kmp_trait_clause *> clauses;
399 kmp_vector<int> devices;
400 bool evaluated =
false;
402 int (*get_num_devices)() = kmp_traits::omp_get_num_devices;
406 for (
int d = 0; d < get_num_devices(); ++d) {
408 devices.push_back(d);
413 bool _match(
int device)
const {
414 if (device < 0 || device >= get_num_devices())
416 for (kmp_trait_clause *clause : clauses) {
417 if (clause->match(device))
424 kmp_trait_context() =
default;
425 ~kmp_trait_context() {
426 for (kmp_trait_clause *clause : clauses)
430 kmp_trait_context(
const kmp_trait_context &) =
delete;
431 kmp_trait_context(kmp_trait_context &&) =
delete;
432 kmp_trait_context &operator=(
const kmp_trait_context &) =
delete;
433 kmp_trait_context &operator=(kmp_trait_context &&) =
delete;
438 static kmp_trait_context *parse_from_spec(kmp_str_ref spec,
439 const char *dbg_name =
nullptr);
441 void add_clause(kmp_trait_clause *clause) {
443 clauses.push_back(clause);
445 if (kmp_trait_expr *expr = clause->get_expr())
446 expr->set_num_devices(get_num_devices);
455 const kmp_vector<int> &evaluate() {
456 trigger_evaluation();
460 const kmp_vector<int> &evaluate()
const {
461 assert(evaluated &&
"kmp_trait_context not evaluated");
467 bool match(
int device) {
return evaluate().contains(device); }
469 bool match(
int device)
const {
470 assert(evaluated &&
"kmp_trait_context not evaluated");
471 return devices.contains(device);
476 void set_num_devices(
int (*num_devices)()) {
477 get_num_devices = num_devices;
478 for (kmp_trait_clause *clause : clauses) {
479 if (kmp_trait_expr *expr = clause->get_expr())
480 expr->set_num_devices(num_devices);
485 void trigger_evaluation() {
491 void *
operator new(
size_t size) {
return KMP_INTERNAL_MALLOC(size); }
492 void operator delete(
void *ptr) { KMP_INTERNAL_FREE(ptr); }
494 bool operator==(
const kmp_trait_context &other)
const {
495 auto clause_comp = [](kmp_trait_clause *
const &a,
496 kmp_trait_clause *
const &b) {
return *a == *b; };
497 return clauses.is_set_equal(other.clauses, clause_comp);
502 const int *begin() {
return evaluate().begin(); }
503 const int *end() {
return evaluate().end(); }
504 const int *begin()
const {
return evaluate().begin(); }
505 const int *end()
const {
return evaluate().end(); }
kmp_str_ref is a non-owning string class (similar to llvm::StringRef).
Represents a single (possibly negated) trait.