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