1 | //===-- flang/lib/Semantics/openmp-modifiers.cpp --------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "flang/Semantics/openmp-modifiers.h" |
10 | |
11 | #include "flang/Parser/parse-tree.h" |
12 | #include "llvm/ADT/ArrayRef.h" |
13 | #include "llvm/Frontend/OpenMP/OMP.h" |
14 | |
15 | #include <algorithm> |
16 | #include <cassert> |
17 | #include <map> |
18 | |
19 | namespace Fortran::semantics { |
20 | using namespace llvm::omp; |
21 | |
22 | /// Find the highest version that exists as a key in the given map, |
23 | /// and is less than or equal to `version`. |
24 | /// Account for "version" not being a value from getOpenMPVersions(). |
25 | template <typename ValueTy> |
26 | static unsigned findVersion( |
27 | unsigned version, const std::map<unsigned, ValueTy> &map) { |
28 | llvm::ArrayRef<unsigned> versions{llvm::omp::getOpenMPVersions()}; |
29 | assert(!versions.empty() && "getOpenMPVersions returned empty list" ); |
30 | version = std::clamp(val: version, lo: versions.front(), hi: versions.back()); |
31 | |
32 | // std::map is sorted with respect to keys, by default in the ascending |
33 | // order. |
34 | unsigned found{0}; |
35 | for (auto &[v, _] : map) { |
36 | if (v <= version) { |
37 | found = v; |
38 | } else { |
39 | break; |
40 | } |
41 | } |
42 | |
43 | // It can happen that the above search will not find any version, for |
44 | // example when the minimum version in the map is higher than the current |
45 | // version. This is really an error, but this situation should be handled |
46 | // gracefully, so make some sensible choice and return it. |
47 | if (found == 0) { |
48 | found = !map.empty() ? map.begin()->first : versions.front(); |
49 | } |
50 | return found; |
51 | } |
52 | |
53 | const OmpProperties &OmpModifierDescriptor::props(unsigned version) const { |
54 | return props_.at(findVersion(version, props_)); |
55 | } |
56 | |
57 | const OmpClauses &OmpModifierDescriptor::clauses(unsigned version) const { |
58 | return clauses_.at(findVersion(version, clauses_)); |
59 | } |
60 | |
61 | unsigned OmpModifierDescriptor::since(llvm::omp::Clause id) const { |
62 | unsigned found{[&]() { |
63 | for (auto &[v, cs] : clauses_) { |
64 | if (cs.test(id)) { |
65 | return v; |
66 | } |
67 | } |
68 | return ~0u; |
69 | }()}; |
70 | |
71 | return found <= 45 ? 0 : found; |
72 | } |
73 | |
74 | // Note: The intent for these functions is to have them be automatically- |
75 | // generated in the future. |
76 | |
77 | template <> |
78 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignment>() { |
79 | static const OmpModifierDescriptor desc{ |
80 | /*name=*/"alignment" , |
81 | /*props=*/ |
82 | { |
83 | {45, {OmpProperty::Unique, OmpProperty::Ultimate, OmpProperty::Post}}, |
84 | }, |
85 | /*clauses=*/ |
86 | { |
87 | {45, {Clause::OMPC_aligned}}, |
88 | }, |
89 | }; |
90 | return desc; |
91 | } |
92 | |
93 | template <> |
94 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignModifier>() { |
95 | static const OmpModifierDescriptor desc{ |
96 | /*name=*/"align-modifier" , |
97 | /*props=*/ |
98 | { |
99 | {51, {OmpProperty::Unique}}, |
100 | }, |
101 | /*clauses=*/ |
102 | { |
103 | {51, {Clause::OMPC_allocate}}, |
104 | }, |
105 | }; |
106 | return desc; |
107 | } |
108 | |
109 | template <> |
110 | const OmpModifierDescriptor & |
111 | OmpGetDescriptor<parser::OmpAllocatorComplexModifier>() { |
112 | static const OmpModifierDescriptor desc{ |
113 | /*name=*/"allocator-complex-modifier" , |
114 | /*props=*/ |
115 | { |
116 | {51, {OmpProperty::Unique}}, |
117 | }, |
118 | /*clauses=*/ |
119 | { |
120 | {51, {Clause::OMPC_allocate}}, |
121 | }, |
122 | }; |
123 | return desc; |
124 | } |
125 | |
126 | template <> |
127 | const OmpModifierDescriptor & |
128 | OmpGetDescriptor<parser::OmpAllocatorSimpleModifier>() { |
129 | static const OmpModifierDescriptor desc{ |
130 | /*name=*/"allocator-simple-modifier" , |
131 | /*props=*/ |
132 | { |
133 | {50, {OmpProperty::Exclusive, OmpProperty::Unique}}, |
134 | }, |
135 | /*clauses=*/ |
136 | { |
137 | {50, {Clause::OMPC_allocate}}, |
138 | }, |
139 | }; |
140 | return desc; |
141 | } |
142 | |
143 | template <> |
144 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpChunkModifier>() { |
145 | static const OmpModifierDescriptor desc{ |
146 | /*name=*/"chunk-modifier" , |
147 | /*props=*/ |
148 | { |
149 | {45, {OmpProperty::Unique}}, |
150 | }, |
151 | /*clauses=*/ |
152 | { |
153 | {45, {Clause::OMPC_schedule}}, |
154 | }, |
155 | }; |
156 | return desc; |
157 | } |
158 | |
159 | template <> |
160 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpContextSelector>() { |
161 | static const OmpModifierDescriptor desc{ |
162 | /*name=*/"context-selector" , |
163 | /*props=*/ |
164 | { |
165 | {50, {OmpProperty::Required, OmpProperty::Unique}}, |
166 | }, |
167 | /*clauses=*/ |
168 | { |
169 | // The MATCH clause takes a selector as an argument, not modifier. |
170 | {50, {Clause::OMPC_when}}, |
171 | }, |
172 | }; |
173 | return desc; |
174 | } |
175 | |
176 | template <> |
177 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDependenceType>() { |
178 | static const OmpModifierDescriptor desc{ |
179 | /*name=*/"dependence-type" , |
180 | /*props=*/ |
181 | { |
182 | {45, {OmpProperty::Required, OmpProperty::Ultimate}}, |
183 | }, |
184 | /*clauses=*/ |
185 | { |
186 | {45, {Clause::OMPC_depend}}, |
187 | {51, {Clause::OMPC_depend, Clause::OMPC_update}}, |
188 | {52, {Clause::OMPC_doacross}}, |
189 | }, |
190 | }; |
191 | return desc; |
192 | } |
193 | |
194 | template <> |
195 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeviceModifier>() { |
196 | static const OmpModifierDescriptor desc{ |
197 | /*name=*/"device-modifier" , |
198 | /*props=*/ |
199 | { |
200 | {45, {OmpProperty::Unique}}, |
201 | }, |
202 | /*clauses=*/ |
203 | { |
204 | {45, {Clause::OMPC_device}}, |
205 | }, |
206 | }; |
207 | return desc; |
208 | } |
209 | |
210 | template <> |
211 | const OmpModifierDescriptor & |
212 | OmpGetDescriptor<parser::OmpDirectiveNameModifier>() { |
213 | static const OmpModifierDescriptor desc{ |
214 | /*name=*/"directive-name-modifier" , |
215 | /*props=*/ |
216 | { |
217 | {45, {OmpProperty::Unique}}, |
218 | }, |
219 | /*clauses=*/ |
220 | { |
221 | {45, {Clause::OMPC_if}}, |
222 | }, |
223 | }; |
224 | return desc; |
225 | } |
226 | |
227 | template <> |
228 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() { |
229 | static const OmpModifierDescriptor desc{ |
230 | /*name=*/"expectation" , |
231 | /*props=*/ |
232 | { |
233 | {51, {OmpProperty::Unique}}, |
234 | }, |
235 | /*clauses=*/ |
236 | { |
237 | {51, {Clause::OMPC_from, Clause::OMPC_to}}, |
238 | }, |
239 | }; |
240 | return desc; |
241 | } |
242 | |
243 | template <> |
244 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropPreference>() { |
245 | static const OmpModifierDescriptor desc{ |
246 | /*name=*/"interop-preference" , |
247 | /*props=*/ |
248 | { |
249 | {52, {OmpProperty::Unique}}, |
250 | }, |
251 | /*clauses=*/ |
252 | { |
253 | {52, {Clause::OMPC_init}}, |
254 | }, |
255 | }; |
256 | return desc; |
257 | } |
258 | |
259 | template <> |
260 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropType>() { |
261 | static const OmpModifierDescriptor desc{ |
262 | /*name=*/"interop-type" , |
263 | /*props=*/ |
264 | { |
265 | {52, {OmpProperty::Required}}, |
266 | }, |
267 | /*clauses=*/ |
268 | { |
269 | {52, {Clause::OMPC_init}}, |
270 | }, |
271 | }; |
272 | return desc; |
273 | } |
274 | |
275 | template <> |
276 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpIterator>() { |
277 | static const OmpModifierDescriptor desc{ |
278 | /*name=*/"iterator" , |
279 | /*props=*/ |
280 | { |
281 | {50, {OmpProperty::Unique}}, |
282 | }, |
283 | /*clauses=*/ |
284 | { |
285 | {50, {Clause::OMPC_affinity, Clause::OMPC_depend}}, |
286 | {51, |
287 | {Clause::OMPC_affinity, Clause::OMPC_depend, Clause::OMPC_from, |
288 | Clause::OMPC_map, Clause::OMPC_to}}, |
289 | }, |
290 | }; |
291 | return desc; |
292 | } |
293 | |
294 | template <> |
295 | const OmpModifierDescriptor & |
296 | OmpGetDescriptor<parser::OmpLastprivateModifier>() { |
297 | static const OmpModifierDescriptor desc{ |
298 | /*name=*/"lastprivate-modifier" , |
299 | /*props=*/ |
300 | { |
301 | {50, {OmpProperty::Unique}}, |
302 | }, |
303 | /*clauses=*/ |
304 | { |
305 | {50, {Clause::OMPC_lastprivate}}, |
306 | }, |
307 | }; |
308 | return desc; |
309 | } |
310 | |
311 | template <> |
312 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() { |
313 | static const OmpModifierDescriptor desc{ |
314 | /*name=*/"linear-modifier" , |
315 | /*props=*/ |
316 | { |
317 | {45, {OmpProperty::Unique}}, |
318 | }, |
319 | /*clauses=*/ |
320 | { |
321 | {45, {Clause::OMPC_linear}}, |
322 | }, |
323 | }; |
324 | return desc; |
325 | } |
326 | |
327 | template <> // |
328 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapper>() { |
329 | static const OmpModifierDescriptor desc{ |
330 | /*name=*/"mapper" , |
331 | /*props=*/ |
332 | { |
333 | {50, {OmpProperty::Unique}}, |
334 | }, |
335 | /*clauses=*/ |
336 | { |
337 | {50, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}}, |
338 | }, |
339 | }; |
340 | return desc; |
341 | } |
342 | |
343 | template <> |
344 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapType>() { |
345 | static const OmpModifierDescriptor desc{ |
346 | /*name=*/"map-type" , |
347 | /*props=*/ |
348 | { |
349 | {45, {OmpProperty::Ultimate}}, |
350 | }, |
351 | /*clauses=*/ |
352 | { |
353 | {45, {Clause::OMPC_map}}, |
354 | }, |
355 | }; |
356 | return desc; |
357 | } |
358 | |
359 | template <> |
360 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapTypeModifier>() { |
361 | static const OmpModifierDescriptor desc{ |
362 | /*name=*/"map-type-modifier" , |
363 | /*props=*/ |
364 | { |
365 | {45, {}}, // Repeatable |
366 | }, |
367 | /*clauses=*/ |
368 | { |
369 | {45, {Clause::OMPC_map}}, |
370 | }, |
371 | }; |
372 | return desc; |
373 | } |
374 | |
375 | template <> |
376 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderModifier>() { |
377 | static const OmpModifierDescriptor desc{ |
378 | /*name=*/"order-modifier" , |
379 | /*props=*/ |
380 | { |
381 | {51, {OmpProperty::Unique}}, |
382 | }, |
383 | /*clauses=*/ |
384 | { |
385 | {51, {Clause::OMPC_order}}, |
386 | }, |
387 | }; |
388 | return desc; |
389 | } |
390 | |
391 | template <> |
392 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderingModifier>() { |
393 | static const OmpModifierDescriptor desc{ |
394 | /*name=*/"ordering-modifier" , |
395 | /*props=*/ |
396 | { |
397 | {45, {OmpProperty::Unique}}, |
398 | }, |
399 | /*clauses=*/ |
400 | { |
401 | {45, {Clause::OMPC_schedule}}, |
402 | }, |
403 | }; |
404 | return desc; |
405 | } |
406 | |
407 | template <> |
408 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPrescriptiveness>() { |
409 | static const OmpModifierDescriptor desc{ |
410 | /*name=*/"prescriptiveness" , |
411 | /*props=*/ |
412 | { |
413 | {51, {OmpProperty::Unique}}, |
414 | }, |
415 | /*clauses=*/ |
416 | { |
417 | {51, {Clause::OMPC_grainsize, Clause::OMPC_num_tasks}}, |
418 | }, |
419 | }; |
420 | return desc; |
421 | } |
422 | |
423 | template <> |
424 | const OmpModifierDescriptor & |
425 | OmpGetDescriptor<parser::OmpReductionIdentifier>() { |
426 | static const OmpModifierDescriptor desc{ |
427 | /*name=*/"reduction-identifier" , |
428 | /*props=*/ |
429 | { |
430 | {45, {OmpProperty::Required, OmpProperty::Ultimate}}, |
431 | }, |
432 | /*clauses=*/ |
433 | { |
434 | {45, {Clause::OMPC_reduction}}, |
435 | {50, |
436 | {Clause::OMPC_in_reduction, Clause::OMPC_reduction, |
437 | Clause::OMPC_task_reduction}}, |
438 | }, |
439 | }; |
440 | return desc; |
441 | } |
442 | |
443 | template <> |
444 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpReductionModifier>() { |
445 | static const OmpModifierDescriptor desc{ |
446 | /*name=*/"reduction-modifier" , |
447 | /*props=*/ |
448 | { |
449 | {45, {OmpProperty::Unique}}, |
450 | }, |
451 | /*clauses=*/ |
452 | { |
453 | {45, {Clause::OMPC_reduction}}, |
454 | }, |
455 | }; |
456 | return desc; |
457 | } |
458 | |
459 | template <> |
460 | const OmpModifierDescriptor & |
461 | OmpGetDescriptor<parser::OmpStepComplexModifier>() { |
462 | static const OmpModifierDescriptor desc{ |
463 | /*name=*/"step-complex-modifier" , |
464 | /*props=*/ |
465 | { |
466 | {52, {OmpProperty::Unique}}, |
467 | }, |
468 | /*clauses=*/ |
469 | { |
470 | {52, {Clause::OMPC_linear}}, |
471 | }, |
472 | }; |
473 | return desc; |
474 | } |
475 | |
476 | template <> |
477 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpStepSimpleModifier>() { |
478 | static const OmpModifierDescriptor desc{ |
479 | /*name=*/"step-simple-modifier" , |
480 | /*props=*/ |
481 | { |
482 | {45, {OmpProperty::Unique, OmpProperty::Exclusive}}, |
483 | }, |
484 | /*clauses=*/ |
485 | { |
486 | {45, {Clause::OMPC_linear}}, |
487 | }, |
488 | }; |
489 | return desc; |
490 | } |
491 | |
492 | template <> |
493 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpTaskDependenceType>() { |
494 | static const OmpModifierDescriptor desc{ |
495 | /*name=*/"task-dependence-type" , |
496 | /*props=*/ |
497 | { |
498 | {45, {OmpProperty::Required, OmpProperty::Ultimate}}, |
499 | }, |
500 | /*clauses=*/ |
501 | { |
502 | {45, {Clause::OMPC_depend}}, |
503 | {51, {Clause::OMPC_depend, Clause::OMPC_update}}, |
504 | }, |
505 | }; |
506 | return desc; |
507 | } |
508 | |
509 | template <> |
510 | const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpVariableCategory>() { |
511 | static const OmpModifierDescriptor desc{ |
512 | /*name=*/"variable-category" , |
513 | /*props=*/ |
514 | { |
515 | {45, {OmpProperty::Required, OmpProperty::Unique}}, |
516 | {50, {OmpProperty::Unique}}, |
517 | }, |
518 | /*clauses=*/ |
519 | { |
520 | {45, {Clause::OMPC_defaultmap}}, |
521 | }, |
522 | }; |
523 | return desc; |
524 | } |
525 | } // namespace Fortran::semantics |
526 | |