xref: /llvm-project/flang/lib/Semantics/openmp-modifiers.cpp (revision 03cbe42627c7a7940b47cc1a2cda0120bc9c6d5e)
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(version, versions.front(), 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::OmpDependenceType>() {
161   static const OmpModifierDescriptor desc{
162       /*name=*/"dependence-type",
163       /*props=*/
164       {
165           {45, {OmpProperty::Required, OmpProperty::Ultimate}},
166       },
167       /*clauses=*/
168       {
169           {45, {Clause::OMPC_depend}},
170           {51, {Clause::OMPC_depend, Clause::OMPC_update}},
171           {52, {Clause::OMPC_doacross}},
172       },
173   };
174   return desc;
175 }
176 
177 template <>
178 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeviceModifier>() {
179   static const OmpModifierDescriptor desc{
180       /*name=*/"device-modifier",
181       /*props=*/
182       {
183           {45, {OmpProperty::Unique}},
184       },
185       /*clauses=*/
186       {
187           {45, {Clause::OMPC_device}},
188       },
189   };
190   return desc;
191 }
192 
193 template <>
194 const OmpModifierDescriptor &
195 OmpGetDescriptor<parser::OmpDirectiveNameModifier>() {
196   static const OmpModifierDescriptor desc{
197       /*name=*/"directive-name-modifier",
198       /*props=*/
199       {
200           {45, {OmpProperty::Unique}},
201       },
202       /*clauses=*/
203       {
204           {45, {Clause::OMPC_if}},
205       },
206   };
207   return desc;
208 }
209 
210 template <>
211 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() {
212   static const OmpModifierDescriptor desc{
213       /*name=*/"expectation",
214       /*props=*/
215       {
216           {51, {OmpProperty::Unique}},
217       },
218       /*clauses=*/
219       {
220           {51, {Clause::OMPC_from, Clause::OMPC_to}},
221       },
222   };
223   return desc;
224 }
225 
226 template <>
227 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpIterator>() {
228   static const OmpModifierDescriptor desc{
229       /*name=*/"iterator",
230       /*props=*/
231       {
232           {50, {OmpProperty::Unique}},
233       },
234       /*clauses=*/
235       {
236           {50, {Clause::OMPC_affinity, Clause::OMPC_depend}},
237           {51,
238               {Clause::OMPC_affinity, Clause::OMPC_depend, Clause::OMPC_from,
239                   Clause::OMPC_map, Clause::OMPC_to}},
240       },
241   };
242   return desc;
243 }
244 
245 template <>
246 const OmpModifierDescriptor &
247 OmpGetDescriptor<parser::OmpLastprivateModifier>() {
248   static const OmpModifierDescriptor desc{
249       /*name=*/"lastprivate-modifier",
250       /*props=*/
251       {
252           {50, {OmpProperty::Unique}},
253       },
254       /*clauses=*/
255       {
256           {50, {Clause::OMPC_lastprivate}},
257       },
258   };
259   return desc;
260 }
261 
262 template <>
263 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() {
264   static const OmpModifierDescriptor desc{
265       /*name=*/"linear-modifier",
266       /*props=*/
267       {
268           {45, {OmpProperty::Unique}},
269       },
270       /*clauses=*/
271       {
272           {45, {Clause::OMPC_linear}},
273       },
274   };
275   return desc;
276 }
277 
278 template <> //
279 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapper>() {
280   static const OmpModifierDescriptor desc{
281       /*name=*/"mapper",
282       /*props=*/
283       {
284           {50, {OmpProperty::Unique}},
285       },
286       /*clauses=*/
287       {
288           {50, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}},
289       },
290   };
291   return desc;
292 }
293 
294 template <>
295 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapType>() {
296   static const OmpModifierDescriptor desc{
297       /*name=*/"map-type",
298       /*props=*/
299       {
300           {45, {OmpProperty::Ultimate}},
301       },
302       /*clauses=*/
303       {
304           {45, {Clause::OMPC_map}},
305       },
306   };
307   return desc;
308 }
309 
310 template <>
311 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapTypeModifier>() {
312   static const OmpModifierDescriptor desc{
313       /*name=*/"map-type-modifier",
314       /*props=*/
315       {
316           {45, {}}, // Repeatable
317       },
318       /*clauses=*/
319       {
320           {45, {Clause::OMPC_map}},
321       },
322   };
323   return desc;
324 }
325 
326 template <>
327 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderModifier>() {
328   static const OmpModifierDescriptor desc{
329       /*name=*/"order-modifier",
330       /*props=*/
331       {
332           {51, {OmpProperty::Unique}},
333       },
334       /*clauses=*/
335       {
336           {51, {Clause::OMPC_order}},
337       },
338   };
339   return desc;
340 }
341 
342 template <>
343 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderingModifier>() {
344   static const OmpModifierDescriptor desc{
345       /*name=*/"ordering-modifier",
346       /*props=*/
347       {
348           {45, {OmpProperty::Unique}},
349       },
350       /*clauses=*/
351       {
352           {45, {Clause::OMPC_schedule}},
353       },
354   };
355   return desc;
356 }
357 
358 template <>
359 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPrescriptiveness>() {
360   static const OmpModifierDescriptor desc{
361       /*name=*/"prescriptiveness",
362       /*props=*/
363       {
364           {51, {OmpProperty::Unique}},
365       },
366       /*clauses=*/
367       {
368           {51, {Clause::OMPC_grainsize, Clause::OMPC_num_tasks}},
369       },
370   };
371   return desc;
372 }
373 
374 template <>
375 const OmpModifierDescriptor &
376 OmpGetDescriptor<parser::OmpReductionIdentifier>() {
377   static const OmpModifierDescriptor desc{
378       /*name=*/"reduction-identifier",
379       /*props=*/
380       {
381           {45, {OmpProperty::Required, OmpProperty::Ultimate}},
382       },
383       /*clauses=*/
384       {
385           {45, {Clause::OMPC_reduction}},
386           {50,
387               {Clause::OMPC_in_reduction, Clause::OMPC_reduction,
388                   Clause::OMPC_task_reduction}},
389       },
390   };
391   return desc;
392 }
393 
394 template <>
395 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpReductionModifier>() {
396   static const OmpModifierDescriptor desc{
397       /*name=*/"reduction-modifier",
398       /*props=*/
399       {
400           {45, {OmpProperty::Unique}},
401       },
402       /*clauses=*/
403       {
404           {45, {Clause::OMPC_reduction}},
405       },
406   };
407   return desc;
408 }
409 
410 template <>
411 const OmpModifierDescriptor &
412 OmpGetDescriptor<parser::OmpStepComplexModifier>() {
413   static const OmpModifierDescriptor desc{
414       /*name=*/"step-complex-modifier",
415       /*props=*/
416       {
417           {52, {OmpProperty::Unique}},
418       },
419       /*clauses=*/
420       {
421           {52, {Clause::OMPC_linear}},
422       },
423   };
424   return desc;
425 }
426 
427 template <>
428 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpStepSimpleModifier>() {
429   static const OmpModifierDescriptor desc{
430       /*name=*/"step-simple-modifier",
431       /*props=*/
432       {
433           {45, {OmpProperty::Unique, OmpProperty::Exclusive}},
434       },
435       /*clauses=*/
436       {
437           {45, {Clause::OMPC_linear}},
438       },
439   };
440   return desc;
441 }
442 
443 template <>
444 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpTaskDependenceType>() {
445   static const OmpModifierDescriptor desc{
446       /*name=*/"task-dependence-type",
447       /*props=*/
448       {
449           {45, {OmpProperty::Required, OmpProperty::Ultimate}},
450       },
451       /*clauses=*/
452       {
453           {45, {Clause::OMPC_depend}},
454           {51, {Clause::OMPC_depend, Clause::OMPC_update}},
455       },
456   };
457   return desc;
458 }
459 
460 template <>
461 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpVariableCategory>() {
462   static const OmpModifierDescriptor desc{
463       /*name=*/"variable-category",
464       /*props=*/
465       {
466           {45, {OmpProperty::Required, OmpProperty::Unique}},
467           {50, {OmpProperty::Unique}},
468       },
469       /*clauses=*/
470       {
471           {45, {Clause::OMPC_defaultmap}},
472       },
473   };
474   return desc;
475 }
476 } // namespace Fortran::semantics
477