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>;
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>()
95#undef DECLARE_DESCRIPTOR
123template <
typename UnionTy>
125 return common::visit(
126 [](
auto &&m) ->
decltype(
auto) {
127 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
128 return OmpGetDescriptor<SpecificTy>();
136template <
typename ClauseTy>
137const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
138 const ClauseTy &clause) {
139 using UnionTy =
typename ClauseTy::Modifier;
140 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
150template <
typename SpecificTy,
typename UnionTy>
151typename std::list<UnionTy>::const_iterator findInRange(
152 typename std::list<UnionTy>::const_iterator begin,
153 typename std::list<UnionTy>::const_iterator end) {
154 for (
auto it{begin}; it != end; ++it) {
155 if (std::holds_alternative<SpecificTy>(it->u)) {
166template <
typename SpecificTy,
typename UnionTy>
167const SpecificTy *OmpGetUniqueModifier(
168 const std::optional<std::list<UnionTy>> &modifiers) {
169 const SpecificTy *found{
nullptr};
171 auto end{modifiers->cend()};
172 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
174 found = &std::get<SpecificTy>(at->u);
181 using VectorTy = std::vector<const SpecificTy *>;
183 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
184 : specificList(list), at(where) {}
197 const SpecificTy *operator*()
const {
return *at; }
199 assert(specificList.get() == other.specificList.get() &&
200 "comparing unrelated iterators");
201 return at == other.at;
204 return !(*
this == other);
208 std::shared_ptr<VectorTy> specificList;
209 typename VectorTy::const_iterator at;
212template <
typename SpecificTy,
typename UnionTy>
213llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
214OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
215 using VectorTy = std::vector<const SpecificTy *>;
216 std::shared_ptr<VectorTy> items(
new VectorTy);
218 for (
auto &m : *modifiers) {
219 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
224 return llvm::iterator_range(
225 OmpSpecificModifierIterator(items, items->begin()),
226 OmpSpecificModifierIterator(items, items->end()));
230template <
typename SpecificTy,
typename UnionTy>
231llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
232OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
234template <
typename SpecificTy,
typename UnionTy>
236 const std::optional<std::list<UnionTy>> &modifiers,
237 const SpecificTy *specific) {
238 if (!modifiers || !specific) {
241 for (
auto &m : *modifiers) {
242 if (std::get_if<SpecificTy>(&m.u) == specific) {
246 llvm_unreachable(
"`specific` must be a member of `modifiers`");
250template <
typename T>
constexpr const T *make_nullptr() {
251 return static_cast<const T *
>(
nullptr);
255template <
typename UnionTy>
256bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
257 llvm::omp::Clause
id, parser::CharBlock clauseSource,
258 SemanticsContext &semaCtx) {
262 unsigned version{semaCtx.langOptions().OpenMPVersion};
264 for (
auto &m : *modifiers) {
265 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
266 unsigned since{desc.since(
id)};
269 semaCtx.Say(m.source,
270 "'%s' modifier is not supported on %s clause"_err_en_US,
272 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
273 }
else if (version < since) {
274 semaCtx.Say(m.source,
275 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
276 desc.name.str(), version / 10, version % 10, since);
287template <
typename SpecificTy,
typename UnionTy>
288bool verifyIfRequired(
const SpecificTy *,
289 const std::optional<std::list<UnionTy>> &modifiers,
290 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
291 unsigned version{semaCtx.langOptions().OpenMPVersion};
292 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
293 if (!desc.props(version).test(OmpProperty::Required)) {
297 bool present{modifiers.has_value()};
298 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
299 return std::holds_alternative<SpecificTy>(m.u);
303 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
311template <
typename UnionTy,
size_t... Idxs>
312bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
313 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
314 std::integer_sequence<size_t, Idxs...>) {
315 using VariantTy =
typename UnionTy::Variant;
316 return (verifyIfRequired(
317 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
318 modifiers, clauseSource, semaCtx) &&
324template <
typename UnionTy>
325bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
326 llvm::omp::Clause
id, parser::CharBlock clauseSource,
327 SemanticsContext &semaCtx) {
328 using VariantTy =
typename UnionTy::Variant;
329 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
330 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
337template <
typename UnionTy,
typename SpecificTy>
338bool verifyIfUnique(
const SpecificTy *,
339 typename std::list<UnionTy>::const_iterator specific,
340 typename std::list<UnionTy>::const_iterator end,
341 SemanticsContext &semaCtx) {
343 assert(specific != end &&
"`specific` must be a valid location");
345 unsigned version{semaCtx.langOptions().OpenMPVersion};
346 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
348 if (!desc.props(version).test(OmpProperty::Unique) &&
349 !desc.props(version).test(OmpProperty::Ultimate)) {
352 if (std::next(specific) != end) {
354 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
356 semaCtx.Say(next->source,
357 "'%s' modifier cannot occur multiple times"_err_en_US,
366template <
typename UnionTy>
367bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
368 llvm::omp::Clause
id, parser::CharBlock clauseSource,
369 SemanticsContext &semaCtx) {
374 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
375 result = common::visit(
377 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
387template <
typename UnionTy>
388bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
389 llvm::omp::Clause
id, parser::CharBlock clauseSource,
390 SemanticsContext &semaCtx) {
391 if (!modifiers || modifiers->size() <= 1) {
394 unsigned version{semaCtx.langOptions().OpenMPVersion};
396 auto first{modifiers->cbegin()};
397 auto last{std::prev(modifiers->cend())};
404 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
408 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
409 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
410 auto &props{desc.props(version)};
412 if (props.test(OmpProperty::Ultimate)) {
413 bool isPre = !props.test(OmpProperty::Post);
414 if (it == (isPre ? last : first)) {
418 llvm::StringRef where{isPre ?
"last" :
"first"};
419 semaCtx.Say(it->source,
420 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
434template <
typename UnionTy>
435bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
436 llvm::omp::Clause
id, parser::CharBlock clauseSource,
437 SemanticsContext &semaCtx) {
438 if (!modifiers || modifiers->size() <= 1) {
441 unsigned version{semaCtx.langOptions().OpenMPVersion};
442 const UnionTy &front{modifiers->front()};
443 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
445 auto second{std::next(modifiers->cbegin())};
446 auto end{modifiers->end()};
448 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
449 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
450 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
451 parser::MessageFormattedText txt(
452 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
453 descExcl.name.str());
454 parser::Message message(excl.source, txt);
456 other.source,
"'%s' provided here"_en_US, descOther.name.str());
457 semaCtx.Say(std::move(message));
460 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
466 size_t frontIndex{front.u.index()};
467 for (
auto it{second}; it != end; ++it) {
468 if (it->u.index() != frontIndex) {
469 emitErrorMessage(front, *it);
480 for (
auto it{second}; it != end; ++it) {
481 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
482 if (desc.props(version).test(OmpProperty::Exclusive)) {
483 emitErrorMessage(*it, front);
493template <
typename ClauseTy>
494bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
495 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
496 auto &modifiers{OmpGetModifiers(clause)};
498 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
499 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
500 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
501 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
502 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
503 return llvm::all_of(results, [](
bool x) {
return x; });
Definition: enum-set.h:28
Definition: char-block.h:28
Definition: parse-tree.h:3643
Definition: parse-tree.h:3635
Definition: parse-tree.h:3659
Definition: parse-tree.h:3651
Definition: parse-tree.h:3669
Definition: parse-tree.h:3703
Definition: parse-tree.h:3712
Definition: parse-tree.h:3730
Definition: parse-tree.h:3744
Definition: parse-tree.h:3753
Definition: parse-tree.h:3761
Definition: parse-tree.h:3770
Definition: parse-tree.h:3798
Definition: parse-tree.h:3787
Definition: parse-tree.h:3779
Definition: parse-tree.h:3822
Definition: parse-tree.h:3813
Definition: parse-tree.h:3831
Definition: parse-tree.h:3843
Definition: parse-tree.h:3852
Definition: parse-tree.h:3861
Definition: parse-tree.h:3869
Definition: parse-tree.h:3879
Definition: parse-tree.h:3890
Definition: openmp-modifiers.h:52
Definition: openmp-modifiers.h:180