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);
112#undef DECLARE_DESCRIPTOR
140template <
typename UnionTy>
142 return common::visit(
143 [](
auto &&m) ->
decltype(
auto) {
144 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
145 return OmpGetDescriptor<SpecificTy>();
153template <
typename ClauseTy>
154const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
155 const ClauseTy &clause) {
156 using UnionTy =
typename ClauseTy::Modifier;
157 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
167template <
typename SpecificTy,
typename UnionTy>
168typename std::list<UnionTy>::const_iterator findInRange(
169 typename std::list<UnionTy>::const_iterator begin,
170 typename std::list<UnionTy>::const_iterator end) {
171 for (
auto it{begin}; it != end; ++it) {
172 if (std::holds_alternative<SpecificTy>(it->u)) {
183template <
typename SpecificTy,
typename UnionTy>
184const SpecificTy *OmpGetUniqueModifier(
185 const std::optional<std::list<UnionTy>> &modifiers) {
186 const SpecificTy *found{
nullptr};
188 auto end{modifiers->cend()};
189 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
191 found = &std::get<SpecificTy>(at->u);
197template <
typename SpecificTy>
struct OmpSpecificModifierIterator {
198 using VectorTy = std::vector<const SpecificTy *>;
199 OmpSpecificModifierIterator(
200 std::shared_ptr<VectorTy> list,
typename VectorTy::const_iterator where)
201 : specificList(list), at(where) {}
203 OmpSpecificModifierIterator &operator++() {
208 OmpSpecificModifierIterator &operator--() {
214 const SpecificTy *operator*()
const {
return *at; }
215 bool operator==(
const OmpSpecificModifierIterator &other)
const {
216 assert(specificList.get() == other.specificList.get() &&
217 "comparing unrelated iterators");
218 return at == other.at;
220 bool operator!=(
const OmpSpecificModifierIterator &other)
const {
221 return !(*
this == other);
225 std::shared_ptr<VectorTy> specificList;
226 typename VectorTy::const_iterator at;
229template <
typename SpecificTy,
typename UnionTy>
230llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
231OmpGetRepeatableModifier(
const std::optional<std::list<UnionTy>> &modifiers) {
232 using VectorTy = std::vector<const SpecificTy *>;
233 std::shared_ptr<VectorTy> items(
new VectorTy);
235 for (
auto &m : *modifiers) {
236 if (
auto *s = std::get_if<SpecificTy>(&m.u)) {
241 return llvm::iterator_range(
247template <
typename SpecificTy,
typename UnionTy>
248llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
249OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) =
delete;
251template <
typename SpecificTy,
typename UnionTy>
252Fortran::parser::CharBlock OmpGetModifierSource(
253 const std::optional<std::list<UnionTy>> &modifiers,
254 const SpecificTy *specific) {
255 if (!modifiers || !specific) {
256 return Fortran::parser::CharBlock{};
258 for (
auto &m : *modifiers) {
259 if (std::get_if<SpecificTy>(&m.u) == specific) {
263 llvm_unreachable(
"`specific` must be a member of `modifiers`");
267template <
typename T>
constexpr const T *make_nullptr() {
268 return static_cast<const T *
>(
nullptr);
272template <
typename UnionTy>
273bool verifyVersions(
const std::optional<std::list<UnionTy>> &modifiers,
274 llvm::omp::Clause
id, parser::CharBlock clauseSource,
275 SemanticsContext &semaCtx) {
279 unsigned version{semaCtx.langOptions().OpenMPVersion};
281 for (
auto &m : *modifiers) {
282 const OmpModifierDescriptor &desc{OmpGetDescriptor(m)};
283 unsigned since{desc.since(
id)};
286 semaCtx.Say(m.source,
287 "'%s' modifier is not supported on %s clause"_err_en_US,
289 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(
id)));
290 }
else if (version < since) {
291 semaCtx.Say(m.source,
292 "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US,
293 desc.name.str(), version / 10, version % 10, since);
304template <
typename SpecificTy,
typename UnionTy>
305bool verifyIfRequired(
const SpecificTy *,
306 const std::optional<std::list<UnionTy>> &modifiers,
307 parser::CharBlock clauseSource, SemanticsContext &semaCtx) {
308 unsigned version{semaCtx.langOptions().OpenMPVersion};
309 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
310 if (!desc.props(version).test(OmpProperty::Required)) {
314 bool present{modifiers.has_value()};
315 present = present && llvm::any_of(*modifiers, [](
auto &&m) {
316 return std::holds_alternative<SpecificTy>(m.u);
320 clauseSource,
"'%s' modifier is required"_err_en_US, desc.name.str());
328template <
typename UnionTy,
size_t... Idxs>
329bool verifyRequiredPack(
const std::optional<std::list<UnionTy>> &modifiers,
330 parser::CharBlock clauseSource, SemanticsContext &semaCtx,
331 std::integer_sequence<size_t, Idxs...>) {
332 using VariantTy =
typename UnionTy::Variant;
333 return (verifyIfRequired(
334 make_nullptr<std::variant_alternative_t<Idxs, VariantTy>>(),
335 modifiers, clauseSource, semaCtx) &&
341template <
typename UnionTy>
342bool verifyRequired(
const std::optional<std::list<UnionTy>> &modifiers,
343 llvm::omp::Clause
id, parser::CharBlock clauseSource,
344 SemanticsContext &semaCtx) {
345 using VariantTy =
typename UnionTy::Variant;
346 return verifyRequiredPack(modifiers, clauseSource, semaCtx,
347 std::make_index_sequence<std::variant_size_v<VariantTy>>{});
354template <
typename UnionTy,
typename SpecificTy>
355bool verifyIfUnique(
const SpecificTy *,
356 typename std::list<UnionTy>::const_iterator specific,
357 typename std::list<UnionTy>::const_iterator end,
358 SemanticsContext &semaCtx) {
360 assert(specific != end &&
"`specific` must be a valid location");
362 unsigned version{semaCtx.langOptions().OpenMPVersion};
363 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
365 if (!desc.props(version).test(OmpProperty::Unique) &&
366 !desc.props(version).test(OmpProperty::Ultimate)) {
369 if (std::next(specific) != end) {
371 detail::findInRange<SpecificTy, UnionTy>(std::next(specific), end)};
373 semaCtx.Say(next->source,
374 "'%s' modifier cannot occur multiple times"_err_en_US,
383template <
typename UnionTy>
384bool verifyUnique(
const std::optional<std::list<UnionTy>> &modifiers,
385 llvm::omp::Clause
id, parser::CharBlock clauseSource,
386 SemanticsContext &semaCtx) {
391 for (
auto it{modifiers->cbegin()}, end{modifiers->cend()}; it != end; ++it) {
392 result = common::visit(
394 return verifyIfUnique<UnionTy>(&m, it, end, semaCtx);
404template <
typename UnionTy>
405bool verifyUltimate(
const std::optional<std::list<UnionTy>> &modifiers,
406 llvm::omp::Clause
id, parser::CharBlock clauseSource,
407 SemanticsContext &semaCtx) {
408 if (!modifiers || modifiers->size() <= 1) {
411 unsigned version{semaCtx.langOptions().OpenMPVersion};
413 auto first{modifiers->cbegin()};
414 auto last{std::prev(modifiers->cend())};
421 for (
auto it{first}, end{modifiers->cend()}; it != end; ++it) {
425 using SpecificTy = llvm::remove_cvref_t<
decltype(m)>;
426 const OmpModifierDescriptor &desc{OmpGetDescriptor<SpecificTy>()};
427 auto &props{desc.props(version)};
429 if (props.test(OmpProperty::Ultimate)) {
430 bool isPre = !props.test(OmpProperty::Post);
431 if (it == (isPre ? last : first)) {
435 llvm::StringRef where{isPre ?
"last" :
"first"};
436 semaCtx.Say(it->source,
437 "'%s' should be the %s modifier"_err_en_US, desc.name.str(),
451template <
typename UnionTy>
452bool verifyExclusive(
const std::optional<std::list<UnionTy>> &modifiers,
453 llvm::omp::Clause
id, parser::CharBlock clauseSource,
454 SemanticsContext &semaCtx) {
455 if (!modifiers || modifiers->size() <= 1) {
458 unsigned version{semaCtx.langOptions().OpenMPVersion};
459 const UnionTy &front{modifiers->front()};
460 const OmpModifierDescriptor &frontDesc{OmpGetDescriptor(front)};
462 auto second{std::next(modifiers->cbegin())};
463 auto end{modifiers->end()};
465 auto emitErrorMessage{[&](
const UnionTy &excl,
const UnionTy &other) {
466 const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)};
467 const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)};
468 parser::MessageFormattedText txt(
469 "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US,
470 descExcl.name.str());
471 parser::Message message(excl.source, txt);
473 other.source,
"'%s' provided here"_en_US, descOther.name.str());
474 semaCtx.Say(std::move(message));
477 if (frontDesc.props(version).test(OmpProperty::Exclusive)) {
483 size_t frontIndex{front.u.index()};
484 for (
auto it{second}; it != end; ++it) {
485 if (it->u.index() != frontIndex) {
486 emitErrorMessage(front, *it);
497 for (
auto it{second}; it != end; ++it) {
498 const OmpModifierDescriptor &desc{OmpGetDescriptor(*it)};
499 if (desc.props(version).test(OmpProperty::Exclusive)) {
500 emitErrorMessage(*it, front);
510template <
typename ClauseTy>
511bool OmpVerifyModifiers(
const ClauseTy &clause, llvm::omp::Clause
id,
513 auto &modifiers{OmpGetModifiers(clause)};
515 detail::verifyVersions(modifiers,
id, clauseSource, semaCtx),
516 detail::verifyRequired(modifiers,
id, clauseSource, semaCtx),
517 detail::verifyUnique(modifiers,
id, clauseSource, semaCtx),
518 detail::verifyUltimate(modifiers,
id, clauseSource, semaCtx),
519 detail::verifyExclusive(modifiers,
id, clauseSource, semaCtx)};
520 return llvm::all_of(results, [](
bool x) {
return x; });
Definition semantics.h:67
Definition parse-tree.h:3582
Definition parse-tree.h:3821
Definition parse-tree.h:3838
Definition parse-tree.h:3830
Definition parse-tree.h:3854
Definition parse-tree.h:3846
Definition parse-tree.h:3866
Definition parse-tree.h:3878
Definition parse-tree.h:3888
Definition parse-tree.h:3899
Definition parse-tree.h:3912
Definition parse-tree.h:3924
Definition parse-tree.h:3945
Definition parse-tree.h:3956
Definition parse-tree.h:3966
Definition parse-tree.h:3975
Definition parse-tree.h:3992
Definition parse-tree.h:4007
Definition parse-tree.h:4018
Definition parse-tree.h:4029
Definition parse-tree.h:4051
Definition parse-tree.h:4059
Definition parse-tree.h:4068
Definition parse-tree.h:4077
Definition parse-tree.h:4111
Definition parse-tree.h:4098
Definition parse-tree.h:4085
Definition parse-tree.h:4135
Definition parse-tree.h:4126
Definition parse-tree.h:4169
Definition parse-tree.h:4178
Definition parse-tree.h:4191
Definition parse-tree.h:4200
Definition parse-tree.h:4210
Definition parse-tree.h:4220
Definition parse-tree.h:4229
Definition parse-tree.h:4237
Definition parse-tree.h:4247
Definition parse-tree.h:4258
Definition parse-tree.h:4271
Definition openmp-modifiers.h:52
Definition openmp-modifiers.h:197