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>()
78DECLARE_DESCRIPTOR(parser::OmpContextSelector);
106#undef DECLARE_DESCRIPTOR
134template <
typename UnionTy>
136 return common::visit(
137 [](
auto &&m) ->
decltype(
auto) {
138 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
139 return OmpGetDescriptor<SpecificTy>();
147template <
typename ClauseTy>
148const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
149 const ClauseTy &clause) {
150 using UnionTy =
typename ClauseTy::Modifier;
151 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
161template <
typename SpecificTy,
typename UnionTy>
162typename std::list<UnionTy>::const_iterator findInRange(
163 typename std::list<UnionTy>::const_iterator begin,
164 typename std::list<UnionTy>::const_iterator end) {
165 for (
auto it{begin}; it != end; ++it) {
166 if (std::holds_alternative<SpecificTy>(it->u)) {
177template <
typename SpecificTy,
typename UnionTy>
178const SpecificTy *OmpGetUniqueModifier(
179 const std::optional<std::list<UnionTy>> &modifiers) {
180 const SpecificTy *found{
nullptr};
182 auto end{modifiers->cend()};
183 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
185 found = &std::get<SpecificTy>(at->u);
191template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
192 using VectorTy = std::vector<const SpecificTy *>;
193 OmpSpecificModifierIterator(
194 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
195 : specificList(list), at(where) {}
197 OmpSpecificModifierIterator &operator++() {
202 OmpSpecificModifierIterator &operator--() {
208 const SpecificTy *operator*()
const {
return *at; }
209 bool operator==(
const OmpSpecificModifierIterator &other)
const {
210 assert(specificList.get() == other.specificList.get() &&
211 "comparing unrelated iterators");
212 return at == other.at;
214 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
215 return !(*
this == other);
219 std::shared_ptr<VectorTy> specificList;
220 typename VectorTy::const_iterator at;
223template <
typename SpecificTy,
typename UnionTy>
224llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
225OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
226 using VectorTy = std::vector<const SpecificTy *>;
227 std::shared_ptr<VectorTy> items(
new VectorTy);
229 for (
auto &m : *modifiers) {
230 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
235 return llvm::iterator_range(
241template <
typename SpecificTy,
typename UnionTy>
242llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
243OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
245template <
typename SpecificTy,
typename UnionTy>
246Fortran::parser::CharBlock OmpGetModifierSource(
247 const std::optional<std::list<UnionTy>> &modifiers,
248 const SpecificTy *specific) {
249 if (!modifiers || !specific) {
250 return Fortran::parser::CharBlock{};
252 for (
auto &m : *modifiers) {
253 if (std::get_if<SpecificTy>(&m.u) == specific) {
257 llvm_unreachable(
"`specific` must be a member of `modifiers`");
261template <
typename T>
constexpr const T *make_nullptr() {
262 return static_cast<const T *
>(
nullptr);
266template <
typename UnionTy>
267bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
268 llvm::omp::Clause
id, parser::CharBlock clauseSource,
269 SemanticsContext &semaCtx) {
273 unsigned version{semaCtx.langOptions().OpenMPVersion};
275 for (
auto &m : *modifiers) {
276 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
277 unsigned since{desc.since(
id)};
280 semaCtx.Say(m.source,
281 "'%s' modifier is not supported on %s clause"_err_en_US,
283 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
284 }
else if (version < since) {
285 semaCtx.Say(m.source,
286 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
287 desc.name.str(), version / 10, version % 10, since);
298template <
typename SpecificTy,
typename UnionTy>
299bool verifyIfRequired(
const SpecificTy *,
300 const std::optional<std::list<UnionTy>> &modifiers,
301 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
302 unsigned version{semaCtx.langOptions().OpenMPVersion};
303 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
304 if (!desc.props(version).test(OmpProperty::Required)) {
308 bool present{modifiers.has_value()};
309 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
310 return std::holds_alternative<SpecificTy>(m.u);
314 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
322template <
typename UnionTy,
size_t... Idxs>
323bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
324 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
325 std::integer_sequence<size_t, Idxs...>) {
326 using VariantTy =
typename UnionTy::Variant;
327 return (verifyIfRequired(
328 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
329 modifiers, clauseSource, semaCtx) &&
335template <
typename UnionTy>
336bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
337 llvm::omp::Clause
id, parser::CharBlock clauseSource,
338 SemanticsContext &semaCtx) {
339 using VariantTy =
typename UnionTy::Variant;
340 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
341 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
348template <
typename UnionTy,
typename SpecificTy>
349bool verifyIfUnique(
const SpecificTy *,
350 typename std::list<UnionTy>::const_iterator specific,
351 typename std::list<UnionTy>::const_iterator end,
352 SemanticsContext &semaCtx) {
354 assert(specific != end &&
"`specific` must be a valid location");
356 unsigned version{semaCtx.langOptions().OpenMPVersion};
357 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
359 if (!desc.props(version).test(OmpProperty::Unique) &&
360 !desc.props(version).test(OmpProperty::Ultimate)) {
363 if (std::next(specific) != end) {
365 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
367 semaCtx.Say(next->source,
368 "'%s' modifier cannot occur multiple times"_err_en_US,
377template <
typename UnionTy>
378bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
379 llvm::omp::Clause
id, parser::CharBlock clauseSource,
380 SemanticsContext &semaCtx) {
385 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
386 result = common::visit(
388 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
398template <
typename UnionTy>
399bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
400 llvm::omp::Clause
id, parser::CharBlock clauseSource,
401 SemanticsContext &semaCtx) {
402 if (!modifiers || modifiers->size() <= 1) {
405 unsigned version{semaCtx.langOptions().OpenMPVersion};
407 auto first{modifiers->cbegin()};
408 auto last{std::prev(modifiers->cend())};
415 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
419 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
420 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
421 auto &props{desc.props(version)};
423 if (props.test(OmpProperty::Ultimate)) {
424 bool isPre = !props.test(OmpProperty::Post);
425 if (it == (isPre ? last : first)) {
429 llvm::StringRef where{isPre ?
"last" :
"first"};
430 semaCtx.Say(it->source,
431 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
445template <
typename UnionTy>
446bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
447 llvm::omp::Clause
id, parser::CharBlock clauseSource,
448 SemanticsContext &semaCtx) {
449 if (!modifiers || modifiers->size() <= 1) {
452 unsigned version{semaCtx.langOptions().OpenMPVersion};
453 const UnionTy &front{modifiers->front()};
454 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
456 auto second{std::next(modifiers->cbegin())};
457 auto end{modifiers->end()};
459 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
460 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
461 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
462 parser::MessageFormattedText txt(
463 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
464 descExcl.name.str());
465 parser::Message message(excl.source, txt);
467 other.source,
"'%s' provided here"_en_US, descOther.name.str());
468 semaCtx.Say(std::move(message));
471 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
477 size_t frontIndex{front.u.index()};
478 for (
auto it{second}; it != end; ++it) {
479 if (it->u.index() != frontIndex) {
480 emitErrorMessage(front, *it);
491 for (
auto it{second}; it != end; ++it) {
492 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
493 if (desc.props(version).test(OmpProperty::Exclusive)) {
494 emitErrorMessage(*it, front);
504template <
typename ClauseTy>
505bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
507 auto &modifiers{OmpGetModifiers(clause)};
509 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
510 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
511 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
512 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
513 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
514 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3521
Definition parse-tree.h:3756
Definition parse-tree.h:3748
Definition parse-tree.h:3772
Definition parse-tree.h:3764
Definition parse-tree.h:3784
Definition parse-tree.h:3794
Definition parse-tree.h:3805
Definition parse-tree.h:3818
Definition parse-tree.h:3830
Definition parse-tree.h:3851
Definition parse-tree.h:3860
Definition parse-tree.h:3878
Definition parse-tree.h:3893
Definition parse-tree.h:3911
Definition parse-tree.h:3920
Definition parse-tree.h:3942
Definition parse-tree.h:3950
Definition parse-tree.h:3959
Definition parse-tree.h:3994
Definition parse-tree.h:3981
Definition parse-tree.h:3968
Definition parse-tree.h:4018
Definition parse-tree.h:4009
Definition parse-tree.h:4028
Definition parse-tree.h:4041
Definition parse-tree.h:4050
Definition parse-tree.h:4060
Definition parse-tree.h:4070
Definition parse-tree.h:4079
Definition parse-tree.h:4087
Definition parse-tree.h:4097
Definition parse-tree.h:4108
Definition parse-tree.h:4121
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:191