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>()
79DECLARE_DESCRIPTOR(parser::OmpContextSelector);
107#undef DECLARE_DESCRIPTOR
135template <
typename UnionTy>
137 return common::visit(
138 [](
auto &&m) ->
decltype(
auto) {
139 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
140 return OmpGetDescriptor<SpecificTy>();
148template <
typename ClauseTy>
149const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
150 const ClauseTy &clause) {
151 using UnionTy =
typename ClauseTy::Modifier;
152 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
162template <
typename SpecificTy,
typename UnionTy>
163typename std::list<UnionTy>::const_iterator findInRange(
164 typename std::list<UnionTy>::const_iterator begin,
165 typename std::list<UnionTy>::const_iterator end) {
166 for (
auto it{begin}; it != end; ++it) {
167 if (std::holds_alternative<SpecificTy>(it->u)) {
178template <
typename SpecificTy,
typename UnionTy>
179const SpecificTy *OmpGetUniqueModifier(
180 const std::optional<std::list<UnionTy>> &modifiers) {
181 const SpecificTy *found{
nullptr};
183 auto end{modifiers->cend()};
184 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
186 found = &std::get<SpecificTy>(at->u);
192template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
193 using VectorTy = std::vector<const SpecificTy *>;
194 OmpSpecificModifierIterator(
195 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
196 : specificList(list), at(where) {}
198 OmpSpecificModifierIterator &operator++() {
203 OmpSpecificModifierIterator &operator--() {
209 const SpecificTy *operator*()
const {
return *at; }
210 bool operator==(
const OmpSpecificModifierIterator &other)
const {
211 assert(specificList.get() == other.specificList.get() &&
212 "comparing unrelated iterators");
213 return at == other.at;
215 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
216 return !(*
this == other);
220 std::shared_ptr<VectorTy> specificList;
221 typename VectorTy::const_iterator at;
224template <
typename SpecificTy,
typename UnionTy>
225llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
226OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
227 using VectorTy = std::vector<const SpecificTy *>;
228 std::shared_ptr<VectorTy> items(
new VectorTy);
230 for (
auto &m : *modifiers) {
231 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
236 return llvm::iterator_range(
242template <
typename SpecificTy,
typename UnionTy>
243llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
244OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
246template <
typename SpecificTy,
typename UnionTy>
247Fortran::parser::CharBlock OmpGetModifierSource(
248 const std::optional<std::list<UnionTy>> &modifiers,
249 const SpecificTy *specific) {
250 if (!modifiers || !specific) {
251 return Fortran::parser::CharBlock{};
253 for (
auto &m : *modifiers) {
254 if (std::get_if<SpecificTy>(&m.u) == specific) {
258 llvm_unreachable(
"`specific` must be a member of `modifiers`");
262template <
typename T>
constexpr const T *make_nullptr() {
263 return static_cast<const T *
>(
nullptr);
267template <
typename UnionTy>
268bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
269 llvm::omp::Clause
id, parser::CharBlock clauseSource,
270 SemanticsContext &semaCtx) {
274 unsigned version{semaCtx.langOptions().OpenMPVersion};
276 for (
auto &m : *modifiers) {
277 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
278 unsigned since{desc.since(
id)};
281 semaCtx.Say(m.source,
282 "'%s' modifier is not supported on %s clause"_err_en_US,
284 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
285 }
else if (version < since) {
286 semaCtx.Say(m.source,
287 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
288 desc.name.str(), version / 10, version % 10, since);
299template <
typename SpecificTy,
typename UnionTy>
300bool verifyIfRequired(
const SpecificTy *,
301 const std::optional<std::list<UnionTy>> &modifiers,
302 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
303 unsigned version{semaCtx.langOptions().OpenMPVersion};
304 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
305 if (!desc.props(version).test(OmpProperty::Required)) {
309 bool present{modifiers.has_value()};
310 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
311 return std::holds_alternative<SpecificTy>(m.u);
315 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
323template <
typename UnionTy,
size_t... Idxs>
324bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
325 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
326 std::integer_sequence<size_t, Idxs...>) {
327 using VariantTy =
typename UnionTy::Variant;
328 return (verifyIfRequired(
329 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
330 modifiers, clauseSource, semaCtx) &&
336template <
typename UnionTy>
337bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
338 llvm::omp::Clause
id, parser::CharBlock clauseSource,
339 SemanticsContext &semaCtx) {
340 using VariantTy =
typename UnionTy::Variant;
341 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
342 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
349template <
typename UnionTy,
typename SpecificTy>
350bool verifyIfUnique(
const SpecificTy *,
351 typename std::list<UnionTy>::const_iterator specific,
352 typename std::list<UnionTy>::const_iterator end,
353 SemanticsContext &semaCtx) {
355 assert(specific != end &&
"`specific` must be a valid location");
357 unsigned version{semaCtx.langOptions().OpenMPVersion};
358 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
360 if (!desc.props(version).test(OmpProperty::Unique) &&
361 !desc.props(version).test(OmpProperty::Ultimate)) {
364 if (std::next(specific) != end) {
366 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
368 semaCtx.Say(next->source,
369 "'%s' modifier cannot occur multiple times"_err_en_US,
378template <
typename UnionTy>
379bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
380 llvm::omp::Clause
id, parser::CharBlock clauseSource,
381 SemanticsContext &semaCtx) {
386 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
387 result = common::visit(
389 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
399template <
typename UnionTy>
400bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
401 llvm::omp::Clause
id, parser::CharBlock clauseSource,
402 SemanticsContext &semaCtx) {
403 if (!modifiers || modifiers->size() <= 1) {
406 unsigned version{semaCtx.langOptions().OpenMPVersion};
408 auto first{modifiers->cbegin()};
409 auto last{std::prev(modifiers->cend())};
416 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
420 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
421 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
422 auto &props{desc.props(version)};
424 if (props.test(OmpProperty::Ultimate)) {
425 bool isPre = !props.test(OmpProperty::Post);
426 if (it == (isPre ? last : first)) {
430 llvm::StringRef where{isPre ?
"last" :
"first"};
431 semaCtx.Say(it->source,
432 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
446template <
typename UnionTy>
447bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
448 llvm::omp::Clause
id, parser::CharBlock clauseSource,
449 SemanticsContext &semaCtx) {
450 if (!modifiers || modifiers->size() <= 1) {
453 unsigned version{semaCtx.langOptions().OpenMPVersion};
454 const UnionTy &front{modifiers->front()};
455 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
457 auto second{std::next(modifiers->cbegin())};
458 auto end{modifiers->end()};
460 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
461 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
462 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
463 parser::MessageFormattedText txt(
464 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
465 descExcl.name.str());
466 parser::Message message(excl.source, txt);
468 other.source,
"'%s' provided here"_en_US, descOther.name.str());
469 semaCtx.Say(std::move(message));
472 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
478 size_t frontIndex{front.u.index()};
479 for (
auto it{second}; it != end; ++it) {
480 if (it->u.index() != frontIndex) {
481 emitErrorMessage(front, *it);
492 for (
auto it{second}; it != end; ++it) {
493 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
494 if (desc.props(version).test(OmpProperty::Exclusive)) {
495 emitErrorMessage(*it, front);
505template <
typename ClauseTy>
506bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
508 auto &modifiers{OmpGetModifiers(clause)};
510 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
511 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
512 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
513 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
514 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
515 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3585
Definition parse-tree.h:3841
Definition parse-tree.h:3833
Definition parse-tree.h:3857
Definition parse-tree.h:3849
Definition parse-tree.h:3869
Definition parse-tree.h:3881
Definition parse-tree.h:3891
Definition parse-tree.h:3902
Definition parse-tree.h:3915
Definition parse-tree.h:3927
Definition parse-tree.h:3948
Definition parse-tree.h:3957
Definition parse-tree.h:3975
Definition parse-tree.h:3990
Definition parse-tree.h:4008
Definition parse-tree.h:4017
Definition parse-tree.h:4039
Definition parse-tree.h:4047
Definition parse-tree.h:4056
Definition parse-tree.h:4091
Definition parse-tree.h:4078
Definition parse-tree.h:4065
Definition parse-tree.h:4115
Definition parse-tree.h:4106
Definition parse-tree.h:4125
Definition parse-tree.h:4138
Definition parse-tree.h:4147
Definition parse-tree.h:4157
Definition parse-tree.h:4167
Definition parse-tree.h:4176
Definition parse-tree.h:4184
Definition parse-tree.h:4194
Definition parse-tree.h:4205
Definition parse-tree.h:4218
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:192