FLANG
openmp-modifiers.h
1//===-- flang/lib/Semantics/openmp-modifiers.h ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_
10#define FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_
11
12#include "flang/Parser/characters.h"
13#include "flang/Parser/parse-tree.h"
14#include "flang/Semantics/openmp-utils.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"
19#include "llvm/Frontend/OpenMP/OMPDescriptors.h"
20
21#include <cassert>
22#include <map>
23#include <memory>
24#include <optional>
25#include <variant>
26
27namespace Fortran::semantics {
28
29// Ref: [5.2:58]
30//
31// Syntactic properties for Clauses, Arguments and Modifiers
32//
33// Inverse properties:
34// not Required -> Optional
35// not Unique -> Repeatable
36// not Exclusive -> Compatible
37// not Ultimate -> Free
38//
39// Clause defaults: Optional, Repeatable, Compatible, Free
40// Argument defaults: Required, Unique, Compatible, Free
41// Modifier defaults: Optional, Unique, Compatible, Free
42//
43// Explanation of terminology:
44//
45// A typical clause with modifier[s] looks like this (with parts that are
46// not relevant here removed):
47// struct OmpSomeClause {
48// struct Modifier {
49// using Variant = std::variant<Specific1, Specific2...>;
50// Variant u;
51// };
52// std::tuple<std::optional<std::list<Modifier>>, ...> t;
53// };
54//
55// The Specific1, etc. refer to parser classes that represent modifiers,
56// e.g. OmpIterator or OmpTaskDependenceType. The Variant type contains
57// all modifiers that are allowed for a given clause. The Modifier class
58// is there to wrap the variant into the form that the parse tree visitor
59// expects, i.e. with traits, member "u", etc.
60//
61// To avoid ambiguities with the word "modifier" (e.g. is it "any modifier",
62// or "this specific modifier"?), the following code uses different terms:
63//
64// - UnionTy: refers to the nested "Modifier" class, i.e.
65// "OmpSomeClause::Modifier" in the example above.
66// - SpecificTy: refers to any of the alternatives, i.e. "Specific1" or
67// "Specific2".
68
69template <typename UnionTy>
70const llvm::omp::descriptor::Modifier &OmpGetDescriptor(
71 const UnionTy &modifier) {
72 return common::visit(
73 [](auto &&m) -> decltype(auto) {
74 using SpecificTy = llvm::remove_cvref_t<decltype(m)>;
75 return llvm::omp::getDescriptor(SpecificTy::Id);
76 },
77 modifier.u);
78}
79
83template <typename ClauseTy>
84const std::optional<std::list<typename ClauseTy::Modifier>> &OmpGetModifiers(
85 const ClauseTy &clause) {
86 using UnionTy = typename ClauseTy::Modifier;
87 return std::get<std::optional<std::list<UnionTy>>>(clause.t);
88}
89
90namespace detail {
97template <typename SpecificTy, typename UnionTy>
98typename std::list<UnionTy>::const_iterator findInRange(
99 typename std::list<UnionTy>::const_iterator begin,
100 typename std::list<UnionTy>::const_iterator end) {
101 for (auto it{begin}; it != end; ++it) {
102 if (std::holds_alternative<SpecificTy>(it->u)) {
103 return it;
104 }
105 }
106 return end;
107}
108} // namespace detail
109
113template <typename SpecificTy, typename UnionTy>
114const SpecificTy *OmpGetUniqueModifier(
115 const std::optional<std::list<UnionTy>> &modifiers) {
116 const SpecificTy *found{nullptr};
117 if (modifiers) {
118 auto end{modifiers->cend()};
119 auto at{detail::findInRange<SpecificTy, UnionTy>(modifiers->cbegin(), end)};
120 if (at != end) {
121 found = &std::get<SpecificTy>(at->u);
122 }
123 }
124 return found;
125}
126
127template <typename SpecificTy> struct OmpSpecificModifierIterator {
128 using VectorTy = std::vector<const SpecificTy *>;
129 OmpSpecificModifierIterator(
130 std::shared_ptr<VectorTy> list, typename VectorTy::const_iterator where)
131 : specificList(list), at(where) {}
132
133 OmpSpecificModifierIterator &operator++() {
134 ++at;
135 return *this;
136 }
137 // OmpSpecificModifierIterator &operator++(int);
138 OmpSpecificModifierIterator &operator--() {
139 --at;
140 return *this;
141 }
142 // OmpSpecificModifierIterator &operator--(int);
143
144 const SpecificTy *operator*() const { return *at; }
145 bool operator==(const OmpSpecificModifierIterator &other) const {
146 assert(specificList.get() == other.specificList.get() &&
147 "comparing unrelated iterators");
148 return at == other.at;
149 }
150 bool operator!=(const OmpSpecificModifierIterator &other) const {
151 return !(*this == other);
152 }
153
154private:
155 std::shared_ptr<VectorTy> specificList;
156 typename VectorTy::const_iterator at;
157};
158
159template <typename SpecificTy, typename UnionTy>
160llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
161OmpGetRepeatableModifier(const std::optional<std::list<UnionTy>> &modifiers) {
162 using VectorTy = std::vector<const SpecificTy *>;
163 std::shared_ptr<VectorTy> items(new VectorTy);
164 if (modifiers) {
165 for (auto &m : *modifiers) {
166 if (auto *s = std::get_if<SpecificTy>(&m.u)) {
167 items->push_back(s);
168 }
169 }
170 }
171 return llvm::iterator_range(
172 OmpSpecificModifierIterator(items, items->begin()),
173 OmpSpecificModifierIterator(items, items->end()));
174}
175
176// Attempt to prevent creating a range based on an expiring modifier list.
177template <typename SpecificTy, typename UnionTy>
178llvm::iterator_range<OmpSpecificModifierIterator<SpecificTy>>
179OmpGetRepeatableModifier(std::optional<std::list<UnionTy>> &&) = delete;
180
181template <typename SpecificTy, typename UnionTy>
182Fortran::parser::CharBlock OmpGetModifierSource(
183 const std::optional<std::list<UnionTy>> &modifiers,
184 const SpecificTy *specific) {
185 if (!modifiers || !specific) {
186 return Fortran::parser::CharBlock{};
187 }
188 for (auto &m : *modifiers) {
189 if (std::get_if<SpecificTy>(&m.u) == specific) {
190 return m.source;
191 }
192 }
193 llvm_unreachable("`specific` must be a member of `modifiers`");
194}
195} // namespace Fortran::semantics
196
197#endif // FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_
Definition openmp-modifiers.h:127