9#ifndef FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_
10#define FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_
12#include "flang/Common/enum-set.h"
13#include "flang/Parser/characters.h"
14#include "flang/Parser/parse-tree.h"
15#include "flang/Semantics/semantics.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/Frontend/OpenMP/OMP.h"
26namespace Fortran::semantics {
47ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post)
48using OmpProperties = common::EnumSet<OmpProperty, OmpProperty_enumSize>;
50 common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
54 const OmpProperties &props(
unsigned version)
const;
55 const OmpClauses &clauses(
unsigned version)
const;
56 unsigned since(llvm::omp::Clause
id)
const;
58 const llvm::StringRef name;
60 const std::map<unsigned, OmpProperties> props_;
62 const std::map<unsigned, OmpClauses> clauses_;
67#define DECLARE_DESCRIPTOR(name) \
68 template <> const OmpModifierDescriptor &OmpGetDescriptor<name>()
80DECLARE_DESCRIPTOR(parser::OmpContextSelector);
113#undef DECLARE_DESCRIPTOR
141template <
typename UnionTy>
143 return common::visit(
144 [](
auto &&m) ->
decltype(
auto) {
145 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
146 return OmpGetDescriptor<SpecificTy>();
154template <
typename ClauseTy>
155const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
156 const ClauseTy &clause) {
157 using UnionTy =
typename ClauseTy::Modifier;
158 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
168template <
typename SpecificTy,
typename UnionTy>
169typename std::list<UnionTy>::const_iterator findInRange(
170 typename std::list<UnionTy>::const_iterator begin,
171 typename std::list<UnionTy>::const_iterator end) {
172 for (
auto it{begin}; it != end; ++it) {
173 if (std::holds_alternative<SpecificTy>(it->u)) {
184template <
typename SpecificTy,
typename UnionTy>
185const SpecificTy *OmpGetUniqueModifier(
186 const std::optional<std::list<UnionTy>> &modifiers) {
187 const SpecificTy *found{
nullptr};
189 auto end{modifiers->cend()};
190 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
192 found = &std::get<SpecificTy>(at->u);
198template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
199 using VectorTy = std::vector<const SpecificTy *>;
200 OmpSpecificModifierIterator(
201 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
202 : specificList(list), at(where) {}
204 OmpSpecificModifierIterator &operator++() {
209 OmpSpecificModifierIterator &operator--() {
215 const SpecificTy *operator*()
const {
return *at; }
216 bool operator==(
const OmpSpecificModifierIterator &other)
const {
217 assert(specificList.get() == other.specificList.get() &&
218 "comparing unrelated iterators");
219 return at == other.at;
221 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
222 return !(*
this == other);
226 std::shared_ptr<VectorTy> specificList;
227 typename VectorTy::const_iterator at;
230template <
typename SpecificTy,
typename UnionTy>
231llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
232OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
233 using VectorTy = std::vector<const SpecificTy *>;
234 std::shared_ptr<VectorTy> items(
new VectorTy);
236 for (
auto &m : *modifiers) {
237 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
242 return llvm::iterator_range(
248template <
typename SpecificTy,
typename UnionTy>
249llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
250OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
252template <
typename SpecificTy,
typename UnionTy>
253Fortran::parser::CharBlock OmpGetModifierSource(
254 const std::optional<std::list<UnionTy>> &modifiers,
255 const SpecificTy *specific) {
256 if (!modifiers || !specific) {
257 return Fortran::parser::CharBlock{};
259 for (
auto &m : *modifiers) {
260 if (std::get_if<SpecificTy>(&m.u) == specific) {
264 llvm_unreachable(
"`specific` must be a member of `modifiers`");
268template <
typename T>
constexpr const T *make_nullptr() {
269 return static_cast<const T *
>(
nullptr);
273template <
typename UnionTy>
274bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
275 llvm::omp::Clause
id, parser::CharBlock clauseSource,
276 SemanticsContext &semaCtx) {
280 unsigned version{semaCtx.langOptions().OpenMPVersion};
282 for (
auto &m : *modifiers) {
283 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
284 unsigned since{desc.since(
id)};
287 semaCtx.Say(m.source,
288 "'%s' modifier is not supported on %s clause"_err_en_US,
290 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
291 }
else if (version < since) {
292 semaCtx.Say(m.source,
293 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
294 desc.name.str(), version / 10, version % 10, since);
305template <
typename SpecificTy,
typename UnionTy>
306bool verifyIfRequired(
const SpecificTy *,
307 const std::optional<std::list<UnionTy>> &modifiers,
308 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
309 unsigned version{semaCtx.langOptions().OpenMPVersion};
310 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
311 if (!desc.props(version).test(OmpProperty::Required)) {
315 bool present{modifiers.has_value()};
316 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
317 return std::holds_alternative<SpecificTy>(m.u);
321 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
329template <
typename UnionTy,
size_t... Idxs>
330bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
331 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
332 std::integer_sequence<size_t, Idxs...>) {
333 using VariantTy =
typename UnionTy::Variant;
334 return (verifyIfRequired(
335 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
336 modifiers, clauseSource, semaCtx) &&
342template <
typename UnionTy>
343bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
344 llvm::omp::Clause
id, parser::CharBlock clauseSource,
345 SemanticsContext &semaCtx) {
346 using VariantTy =
typename UnionTy::Variant;
347 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
348 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
355template <
typename UnionTy,
typename SpecificTy>
356bool verifyIfUnique(
const SpecificTy *,
357 typename std::list<UnionTy>::const_iterator specific,
358 typename std::list<UnionTy>::const_iterator end,
359 SemanticsContext &semaCtx) {
361 assert(specific != end &&
"`specific` must be a valid location");
363 unsigned version{semaCtx.langOptions().OpenMPVersion};
364 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
366 if (!desc.props(version).test(OmpProperty::Unique) &&
367 !desc.props(version).test(OmpProperty::Ultimate)) {
370 if (std::next(specific) != end) {
372 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
374 semaCtx.Say(next->source,
375 "'%s' modifier cannot occur multiple times"_err_en_US,
384template <
typename UnionTy>
385bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
386 llvm::omp::Clause
id, parser::CharBlock clauseSource,
387 SemanticsContext &semaCtx) {
392 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
393 result = common::visit(
395 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
405template <
typename UnionTy>
406bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
407 llvm::omp::Clause
id, parser::CharBlock clauseSource,
408 SemanticsContext &semaCtx) {
409 if (!modifiers || modifiers->size() <= 1) {
412 unsigned version{semaCtx.langOptions().OpenMPVersion};
414 auto first{modifiers->cbegin()};
415 auto last{std::prev(modifiers->cend())};
422 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
426 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
427 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
428 auto &props{desc.props(version)};
430 if (props.test(OmpProperty::Ultimate)) {
431 bool isPre = !props.test(OmpProperty::Post);
432 if (it == (isPre ? last : first)) {
436 llvm::StringRef where{isPre ?
"last" :
"first"};
437 semaCtx.Say(it->source,
438 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
452template <
typename UnionTy>
453bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
454 llvm::omp::Clause
id, parser::CharBlock clauseSource,
455 SemanticsContext &semaCtx) {
456 if (!modifiers || modifiers->size() <= 1) {
459 unsigned version{semaCtx.langOptions().OpenMPVersion};
460 const UnionTy &front{modifiers->front()};
461 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
463 auto second{std::next(modifiers->cbegin())};
464 auto end{modifiers->end()};
466 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
467 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
468 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
469 parser::MessageFormattedText txt(
470 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
471 descExcl.name.str());
472 parser::Message message(excl.source, txt);
474 other.source,
"'%s' provided here"_en_US, descOther.name.str());
475 semaCtx.Say(std::move(message));
478 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
484 size_t frontIndex{front.u.index()};
485 for (
auto it{second}; it != end; ++it) {
486 if (it->u.index() != frontIndex) {
487 emitErrorMessage(front, *it);
498 for (
auto it{second}; it != end; ++it) {
499 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
500 if (desc.props(version).test(OmpProperty::Exclusive)) {
501 emitErrorMessage(*it, front);
511template <
typename ClauseTy>
512bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
514 auto &modifiers{OmpGetModifiers(clause)};
516 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
517 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
518 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
519 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
520 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
521 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3678
Definition parse-tree.h:3908
Definition parse-tree.h:3925
Definition parse-tree.h:3917
Definition parse-tree.h:3941
Definition parse-tree.h:3933
Definition parse-tree.h:3953
Definition parse-tree.h:3965
Definition parse-tree.h:3975
Definition parse-tree.h:3986
Definition parse-tree.h:3999
Definition parse-tree.h:4011
Definition parse-tree.h:4032
Definition parse-tree.h:4043
Definition parse-tree.h:4053
Definition parse-tree.h:4062
Definition parse-tree.h:4079
Definition parse-tree.h:4094
Definition parse-tree.h:4105
Definition parse-tree.h:4116
Definition parse-tree.h:4138
Definition parse-tree.h:4146
Definition parse-tree.h:4155
Definition parse-tree.h:4170
Definition parse-tree.h:4182
Definition parse-tree.h:4216
Definition parse-tree.h:4203
Definition parse-tree.h:4190
Definition parse-tree.h:4240
Definition parse-tree.h:4231
Definition parse-tree.h:4274
Definition parse-tree.h:4283
Definition parse-tree.h:4296
Definition parse-tree.h:4305
Definition parse-tree.h:4315
Definition parse-tree.h:4325
Definition parse-tree.h:4334
Definition parse-tree.h:4342
Definition parse-tree.h:4352
Definition parse-tree.h:4363
Definition parse-tree.h:4376
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:198