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);
111#undef DECLARE_DESCRIPTOR
139template <
typename UnionTy>
141 return common::visit(
142 [](
auto &&m) ->
decltype(
auto) {
143 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
144 return OmpGetDescriptor<SpecificTy>();
152template <
typename ClauseTy>
153const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
154 const ClauseTy &clause) {
155 using UnionTy =
typename ClauseTy::Modifier;
156 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
166template <
typename SpecificTy,
typename UnionTy>
167typename std::list<UnionTy>::const_iterator findInRange(
168 typename std::list<UnionTy>::const_iterator begin,
169 typename std::list<UnionTy>::const_iterator end) {
170 for (
auto it{begin}; it != end; ++it) {
171 if (std::holds_alternative<SpecificTy>(it->u)) {
182template <
typename SpecificTy,
typename UnionTy>
183const SpecificTy *OmpGetUniqueModifier(
184 const std::optional<std::list<UnionTy>> &modifiers) {
185 const SpecificTy *found{
nullptr};
187 auto end{modifiers->cend()};
188 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
190 found = &std::get<SpecificTy>(at->u);
196template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
197 using VectorTy = std::vector<const SpecificTy *>;
198 OmpSpecificModifierIterator(
199 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
200 : specificList(list), at(where) {}
202 OmpSpecificModifierIterator &operator++() {
207 OmpSpecificModifierIterator &operator--() {
213 const SpecificTy *operator*()
const {
return *at; }
214 bool operator==(
const OmpSpecificModifierIterator &other)
const {
215 assert(specificList.get() == other.specificList.get() &&
216 "comparing unrelated iterators");
217 return at == other.at;
219 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
220 return !(*
this == other);
224 std::shared_ptr<VectorTy> specificList;
225 typename VectorTy::const_iterator at;
228template <
typename SpecificTy,
typename UnionTy>
229llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
230OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
231 using VectorTy = std::vector<const SpecificTy *>;
232 std::shared_ptr<VectorTy> items(
new VectorTy);
234 for (
auto &m : *modifiers) {
235 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
240 return llvm::iterator_range(
246template <
typename SpecificTy,
typename UnionTy>
247llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
248OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
250template <
typename SpecificTy,
typename UnionTy>
251Fortran::parser::CharBlock OmpGetModifierSource(
252 const std::optional<std::list<UnionTy>> &modifiers,
253 const SpecificTy *specific) {
254 if (!modifiers || !specific) {
255 return Fortran::parser::CharBlock{};
257 for (
auto &m : *modifiers) {
258 if (std::get_if<SpecificTy>(&m.u) == specific) {
262 llvm_unreachable(
"`specific` must be a member of `modifiers`");
266template <
typename T>
constexpr const T *make_nullptr() {
267 return static_cast<const T *
>(
nullptr);
271template <
typename UnionTy>
272bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
273 llvm::omp::Clause
id, parser::CharBlock clauseSource,
274 SemanticsContext &semaCtx) {
278 unsigned version{semaCtx.langOptions().OpenMPVersion};
280 for (
auto &m : *modifiers) {
281 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
282 unsigned since{desc.since(
id)};
285 semaCtx.Say(m.source,
286 "'%s' modifier is not supported on %s clause"_err_en_US,
288 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
289 }
else if (version < since) {
290 semaCtx.Say(m.source,
291 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
292 desc.name.str(), version / 10, version % 10, since);
303template <
typename SpecificTy,
typename UnionTy>
304bool verifyIfRequired(
const SpecificTy *,
305 const std::optional<std::list<UnionTy>> &modifiers,
306 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
307 unsigned version{semaCtx.langOptions().OpenMPVersion};
308 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
309 if (!desc.props(version).test(OmpProperty::Required)) {
313 bool present{modifiers.has_value()};
314 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
315 return std::holds_alternative<SpecificTy>(m.u);
319 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
327template <
typename UnionTy,
size_t... Idxs>
328bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
329 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
330 std::integer_sequence<size_t, Idxs...>) {
331 using VariantTy =
typename UnionTy::Variant;
332 return (verifyIfRequired(
333 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
334 modifiers, clauseSource, semaCtx) &&
340template <
typename UnionTy>
341bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
342 llvm::omp::Clause
id, parser::CharBlock clauseSource,
343 SemanticsContext &semaCtx) {
344 using VariantTy =
typename UnionTy::Variant;
345 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
346 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
353template <
typename UnionTy,
typename SpecificTy>
354bool verifyIfUnique(
const SpecificTy *,
355 typename std::list<UnionTy>::const_iterator specific,
356 typename std::list<UnionTy>::const_iterator end,
357 SemanticsContext &semaCtx) {
359 assert(specific != end &&
"`specific` must be a valid location");
361 unsigned version{semaCtx.langOptions().OpenMPVersion};
362 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
364 if (!desc.props(version).test(OmpProperty::Unique) &&
365 !desc.props(version).test(OmpProperty::Ultimate)) {
368 if (std::next(specific) != end) {
370 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
372 semaCtx.Say(next->source,
373 "'%s' modifier cannot occur multiple times"_err_en_US,
382template <
typename UnionTy>
383bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
384 llvm::omp::Clause
id, parser::CharBlock clauseSource,
385 SemanticsContext &semaCtx) {
390 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
391 result = common::visit(
393 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
403template <
typename UnionTy>
404bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
405 llvm::omp::Clause
id, parser::CharBlock clauseSource,
406 SemanticsContext &semaCtx) {
407 if (!modifiers || modifiers->size() <= 1) {
410 unsigned version{semaCtx.langOptions().OpenMPVersion};
412 auto first{modifiers->cbegin()};
413 auto last{std::prev(modifiers->cend())};
420 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
424 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
425 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
426 auto &props{desc.props(version)};
428 if (props.test(OmpProperty::Ultimate)) {
429 bool isPre = !props.test(OmpProperty::Post);
430 if (it == (isPre ? last : first)) {
434 llvm::StringRef where{isPre ?
"last" :
"first"};
435 semaCtx.Say(it->source,
436 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
450template <
typename UnionTy>
451bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
452 llvm::omp::Clause
id, parser::CharBlock clauseSource,
453 SemanticsContext &semaCtx) {
454 if (!modifiers || modifiers->size() <= 1) {
457 unsigned version{semaCtx.langOptions().OpenMPVersion};
458 const UnionTy &front{modifiers->front()};
459 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
461 auto second{std::next(modifiers->cbegin())};
462 auto end{modifiers->end()};
464 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
465 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
466 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
467 parser::MessageFormattedText txt(
468 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
469 descExcl.name.str());
470 parser::Message message(excl.source, txt);
472 other.source,
"'%s' provided here"_en_US, descOther.name.str());
473 semaCtx.Say(std::move(message));
476 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
482 size_t frontIndex{front.u.index()};
483 for (
auto it{second}; it != end; ++it) {
484 if (it->u.index() != frontIndex) {
485 emitErrorMessage(front, *it);
496 for (
auto it{second}; it != end; ++it) {
497 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
498 if (desc.props(version).test(OmpProperty::Exclusive)) {
499 emitErrorMessage(*it, front);
509template <
typename ClauseTy>
510bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
512 auto &modifiers{OmpGetModifiers(clause)};
514 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
515 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
516 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
517 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
518 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
519 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3605
Definition parse-tree.h:3844
Definition parse-tree.h:3861
Definition parse-tree.h:3853
Definition parse-tree.h:3877
Definition parse-tree.h:3869
Definition parse-tree.h:3889
Definition parse-tree.h:3901
Definition parse-tree.h:3911
Definition parse-tree.h:3922
Definition parse-tree.h:3935
Definition parse-tree.h:3947
Definition parse-tree.h:3968
Definition parse-tree.h:3977
Definition parse-tree.h:3986
Definition parse-tree.h:4003
Definition parse-tree.h:4018
Definition parse-tree.h:4029
Definition parse-tree.h:4074
Definition parse-tree.h:4096
Definition parse-tree.h:4104
Definition parse-tree.h:4113
Definition parse-tree.h:4122
Definition parse-tree.h:4156
Definition parse-tree.h:4143
Definition parse-tree.h:4130
Definition parse-tree.h:4180
Definition parse-tree.h:4171
Definition parse-tree.h:4063
Definition parse-tree.h:4189
Definition parse-tree.h:4202
Definition parse-tree.h:4211
Definition parse-tree.h:4221
Definition parse-tree.h:4231
Definition parse-tree.h:4240
Definition parse-tree.h:4248
Definition parse-tree.h:4258
Definition parse-tree.h:4269
Definition parse-tree.h:4282
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:196