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);
109#undef DECLARE_DESCRIPTOR
137template <
typename UnionTy>
139 return common::visit(
140 [](
auto &&m) ->
decltype(
auto) {
141 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
142 return OmpGetDescriptor<SpecificTy>();
150template <
typename ClauseTy>
151const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
152 const ClauseTy &clause) {
153 using UnionTy =
typename ClauseTy::Modifier;
154 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
164template <
typename SpecificTy,
typename UnionTy>
165typename std::list<UnionTy>::const_iterator findInRange(
166 typename std::list<UnionTy>::const_iterator begin,
167 typename std::list<UnionTy>::const_iterator end) {
168 for (
auto it{begin}; it != end; ++it) {
169 if (std::holds_alternative<SpecificTy>(it->u)) {
180template <
typename SpecificTy,
typename UnionTy>
181const SpecificTy *OmpGetUniqueModifier(
182 const std::optional<std::list<UnionTy>> &modifiers) {
183 const SpecificTy *found{
nullptr};
185 auto end{modifiers->cend()};
186 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
188 found = &std::get<SpecificTy>(at->u);
194template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
195 using VectorTy = std::vector<const SpecificTy *>;
196 OmpSpecificModifierIterator(
197 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
198 : specificList(list), at(where) {}
200 OmpSpecificModifierIterator &operator++() {
205 OmpSpecificModifierIterator &operator--() {
211 const SpecificTy *operator*()
const {
return *at; }
212 bool operator==(
const OmpSpecificModifierIterator &other)
const {
213 assert(specificList.get() == other.specificList.get() &&
214 "comparing unrelated iterators");
215 return at == other.at;
217 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
218 return !(*
this == other);
222 std::shared_ptr<VectorTy> specificList;
223 typename VectorTy::const_iterator at;
226template <
typename SpecificTy,
typename UnionTy>
227llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
228OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
229 using VectorTy = std::vector<const SpecificTy *>;
230 std::shared_ptr<VectorTy> items(
new VectorTy);
232 for (
auto &m : *modifiers) {
233 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
238 return llvm::iterator_range(
244template <
typename SpecificTy,
typename UnionTy>
245llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
246OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
248template <
typename SpecificTy,
typename UnionTy>
249Fortran::parser::CharBlock OmpGetModifierSource(
250 const std::optional<std::list<UnionTy>> &modifiers,
251 const SpecificTy *specific) {
252 if (!modifiers || !specific) {
253 return Fortran::parser::CharBlock{};
255 for (
auto &m : *modifiers) {
256 if (std::get_if<SpecificTy>(&m.u) == specific) {
260 llvm_unreachable(
"`specific` must be a member of `modifiers`");
264template <
typename T>
constexpr const T *make_nullptr() {
265 return static_cast<const T *
>(
nullptr);
269template <
typename UnionTy>
270bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
271 llvm::omp::Clause
id, parser::CharBlock clauseSource,
272 SemanticsContext &semaCtx) {
276 unsigned version{semaCtx.langOptions().OpenMPVersion};
278 for (
auto &m : *modifiers) {
279 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
280 unsigned since{desc.since(
id)};
283 semaCtx.Say(m.source,
284 "'%s' modifier is not supported on %s clause"_err_en_US,
286 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
287 }
else if (version < since) {
288 semaCtx.Say(m.source,
289 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
290 desc.name.str(), version / 10, version % 10, since);
301template <
typename SpecificTy,
typename UnionTy>
302bool verifyIfRequired(
const SpecificTy *,
303 const std::optional<std::list<UnionTy>> &modifiers,
304 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
305 unsigned version{semaCtx.langOptions().OpenMPVersion};
306 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
307 if (!desc.props(version).test(OmpProperty::Required)) {
311 bool present{modifiers.has_value()};
312 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
313 return std::holds_alternative<SpecificTy>(m.u);
317 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
325template <
typename UnionTy,
size_t... Idxs>
326bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
327 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
328 std::integer_sequence<size_t, Idxs...>) {
329 using VariantTy =
typename UnionTy::Variant;
330 return (verifyIfRequired(
331 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
332 modifiers, clauseSource, semaCtx) &&
338template <
typename UnionTy>
339bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
340 llvm::omp::Clause
id, parser::CharBlock clauseSource,
341 SemanticsContext &semaCtx) {
342 using VariantTy =
typename UnionTy::Variant;
343 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
344 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
351template <
typename UnionTy,
typename SpecificTy>
352bool verifyIfUnique(
const SpecificTy *,
353 typename std::list<UnionTy>::const_iterator specific,
354 typename std::list<UnionTy>::const_iterator end,
355 SemanticsContext &semaCtx) {
357 assert(specific != end &&
"`specific` must be a valid location");
359 unsigned version{semaCtx.langOptions().OpenMPVersion};
360 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
362 if (!desc.props(version).test(OmpProperty::Unique) &&
363 !desc.props(version).test(OmpProperty::Ultimate)) {
366 if (std::next(specific) != end) {
368 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
370 semaCtx.Say(next->source,
371 "'%s' modifier cannot occur multiple times"_err_en_US,
380template <
typename UnionTy>
381bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
382 llvm::omp::Clause
id, parser::CharBlock clauseSource,
383 SemanticsContext &semaCtx) {
388 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
389 result = common::visit(
391 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
401template <
typename UnionTy>
402bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
403 llvm::omp::Clause
id, parser::CharBlock clauseSource,
404 SemanticsContext &semaCtx) {
405 if (!modifiers || modifiers->size() <= 1) {
408 unsigned version{semaCtx.langOptions().OpenMPVersion};
410 auto first{modifiers->cbegin()};
411 auto last{std::prev(modifiers->cend())};
418 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
422 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
423 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
424 auto &props{desc.props(version)};
426 if (props.test(OmpProperty::Ultimate)) {
427 bool isPre = !props.test(OmpProperty::Post);
428 if (it == (isPre ? last : first)) {
432 llvm::StringRef where{isPre ?
"last" :
"first"};
433 semaCtx.Say(it->source,
434 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
448template <
typename UnionTy>
449bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
450 llvm::omp::Clause
id, parser::CharBlock clauseSource,
451 SemanticsContext &semaCtx) {
452 if (!modifiers || modifiers->size() <= 1) {
455 unsigned version{semaCtx.langOptions().OpenMPVersion};
456 const UnionTy &front{modifiers->front()};
457 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
459 auto second{std::next(modifiers->cbegin())};
460 auto end{modifiers->end()};
462 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
463 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
464 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
465 parser::MessageFormattedText txt(
466 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
467 descExcl.name.str());
468 parser::Message message(excl.source, txt);
470 other.source,
"'%s' provided here"_en_US, descOther.name.str());
471 semaCtx.Say(std::move(message));
474 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
480 size_t frontIndex{front.u.index()};
481 for (
auto it{second}; it != end; ++it) {
482 if (it->u.index() != frontIndex) {
483 emitErrorMessage(front, *it);
494 for (
auto it{second}; it != end; ++it) {
495 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
496 if (desc.props(version).test(OmpProperty::Exclusive)) {
497 emitErrorMessage(*it, front);
507template <
typename ClauseTy>
508bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
510 auto &modifiers{OmpGetModifiers(clause)};
512 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
513 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
514 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
515 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
516 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
517 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3595
Definition parse-tree.h:3834
Definition parse-tree.h:3851
Definition parse-tree.h:3843
Definition parse-tree.h:3867
Definition parse-tree.h:3859
Definition parse-tree.h:3879
Definition parse-tree.h:3891
Definition parse-tree.h:3901
Definition parse-tree.h:3912
Definition parse-tree.h:3925
Definition parse-tree.h:3937
Definition parse-tree.h:3958
Definition parse-tree.h:3967
Definition parse-tree.h:3985
Definition parse-tree.h:4000
Definition parse-tree.h:4011
Definition parse-tree.h:4029
Definition parse-tree.h:4038
Definition parse-tree.h:4060
Definition parse-tree.h:4068
Definition parse-tree.h:4077
Definition parse-tree.h:4112
Definition parse-tree.h:4099
Definition parse-tree.h:4086
Definition parse-tree.h:4136
Definition parse-tree.h:4127
Definition parse-tree.h:4145
Definition parse-tree.h:4158
Definition parse-tree.h:4167
Definition parse-tree.h:4177
Definition parse-tree.h:4187
Definition parse-tree.h:4196
Definition parse-tree.h:4204
Definition parse-tree.h:4214
Definition parse-tree.h:4225
Definition parse-tree.h:4238
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:194