13#ifndef FORTRAN_PARSER_OPENMP_UTILS_H
14#define FORTRAN_PARSER_OPENMP_UTILS_H
16#include "flang/Common/indirection.h"
17#include "flang/Common/template.h"
18#include "flang/Parser/parse-tree.h"
19#include "llvm/ADT/iterator_range.h"
20#include "llvm/Frontend/OpenMP/OMP.h"
30namespace Fortran::parser::omp {
32template <
typename T>
constexpr auto addr_if(std::optional<T> &x) {
33 return x ? &*x :
nullptr;
35template <
typename T>
constexpr auto addr_if(
const std::optional<T> &x) {
36 return x ? &*x :
nullptr;
39const parser::Designator *GetDesignatorFromObj(
const parser::OmpObject &
object);
40const parser::DataRef *GetDataRefFromObj(
const parser::OmpObject &
object);
41const parser::ArrayElement *GetArrayElementFromObj(
42 const parser::OmpObject &
object);
43std::optional<parser::CharBlock> GetObjectSource(
44 const parser::OmpObject &
object);
45const parser::OmpObject *GetArgumentObject(
const parser::OmpArgument &argument);
47const OmpDirectiveSpecification &GetOmpDirectiveSpecification(
48 const OpenMPConstruct &x);
49const OmpDirectiveSpecification &GetOmpDirectiveSpecification(
50 const OpenMPDeclarativeConstruct &x);
55 llvm::omp::Directive
id = llvm::omp::Directive::OMPD_unknown) {
67 if (
auto &spec{std::get<std::optional<OmpDirectiveSpecification>>(x.t)}) {
68 return spec->DirName();
70 return MakeName({}, llvm::omp::Directive::OMPD_section);
81 if constexpr (WrapperTrait<T>) {
82 return GetOmpDirectiveName(x.v);
83 }
else if constexpr (TupleTrait<T>) {
84 if constexpr (std::is_base_of_v<OmpBlockConstruct, T>) {
85 return std::get<OmpBeginDirective>(x.t).DirName();
88 x.t, std::make_index_sequence<std::tuple_size_v<
decltype(x.t)>>{});
90 }
else if constexpr (UnionTrait<T>) {
92 [](
auto &&s) {
return GetOmpDirectiveName(s); }, x.u);
98 template <
typename... Ts,
size_t... Is>
100 const std::tuple<Ts...> &t, std::index_sequence<Is...>) {
103 if (name.v == llvm::omp::Directive::OMPD_unknown) {
107 n.v == llvm::omp::Directive::OMPD_unknown &&
"Conflicting names");
110 (accumulate(GetOmpDirectiveName(std::get<Is>(t))), ...);
114 template <
typename T>
116 return GetOmpDirectiveName(x.value());
122 return detail::DirectiveNameScope::GetOmpDirectiveName(x);
125std::string GetUpperName(llvm::omp::Clause
id,
unsigned version);
126std::string GetUpperName(llvm::omp::Directive
id,
unsigned version);
136 template <
typename T>
static const OmpObjectList *Get(
const T &x) {
137 if constexpr (std::is_same_v<OmpObjectList, T>) {
139 }
else if constexpr (WrapperTrait<T>) {
141 }
else if constexpr (UnionTrait<T>) {
142 return std::visit([](
auto &&s) {
return Get(s); }, x.u);
143 }
else if constexpr (TupleTrait<T>) {
145 x.t, std::make_index_sequence<std::tuple_size_v<
decltype(x.t)>>{});
146 }
else if constexpr (ConstraintTrait<T>) {
153 template <
typename T>
155 return Get(x.value());
158 template <
typename... Ts,
size_t... Is>
160 const std::tuple<Ts...> &t, std::index_sequence<Is...>) {
162 ((objects = objects ? objects : Get(std::get<Is>(t))), ...);
168template <
typename T>
const OmpObjectList *GetOmpObjectList(
const T &clause) {
169 static_assert(std::is_class_v<T>,
"Unexpected argument type");
170 return detail::OmpObjectListScope::Get(clause);
175 for (
const OmpArgument &arg : spec.Arguments().v) {
176 if (
auto *t{std::get_if<T>(&arg.u)}) {
183const OmpClause *FindClause(
184 const OmpDirectiveSpecification &spec, llvm::omp::Clause clauseId);
186const BlockConstruct *GetFortranBlockConstruct(
187 const ExecutionPartConstruct &epc);
188const Block &GetInnermostExecPart(
const Block &block);
189bool IsStrictlyStructuredBlock(
const Block &block);
191const OmpCombinerExpression *GetCombinerExpr(
const OmpReductionSpecifier &x);
192const OmpCombinerExpression *GetCombinerExpr(
const OmpClause &x);
193const OmpInitializerExpression *GetInitializerExpr(
const OmpClause &x);
196 std::vector<const OmpAllocateDirective *> dirs;
202template <
typename R,
typename =
void,
typename =
void>
struct is_range {
203 static constexpr bool value{
false};
208 std::void_t<decltype(std::declval<R>().begin())>,
209 std::void_t<decltype(std::declval<R>().end())>> {
210 static constexpr bool value{
true};
213template <
typename R>
constexpr bool is_range_v = is_range<R>::value;
243struct ExecutionPartIterator {
250 using IteratorType = Block::const_iterator;
251 using IteratorRange = llvm::iterator_range<IteratorType>;
255 struct IteratorGauge :
public IteratorRange {
256 IteratorGauge(IteratorType b, IteratorType e)
257 : IteratorRange(b, e), at(b) {}
258 IteratorGauge(IteratorRange r) : IteratorRange(r), at(r.begin()) {}
260 bool atEnd()
const {
return at == end(); }
266 : location(b, e), owner(c) {}
267 template <
typename R>
269 : location(r), owner(c) {}
270 Construct(
const Construct &c) =
default;
278 ExecutionPartIterator() =
default;
280 ExecutionPartIterator(IteratorType b, IteratorType e, Step s = Step::Default,
283 stack_.emplace_back(b, e, c);
286 template <
typename R,
typename = std::enable_if_t<is_range_v<R>>>
301 bool valid()
const {
return !stack_.empty(); }
303 const std::vector<Construct> &stack()
const {
return stack_; }
304 decltype(
auto)
operator*()
const {
return *at(); }
305 bool operator==(
const ExecutionPartIterator &other)
const {
306 if (valid() != other.valid()) {
311 stack_.back().location.at == other.stack_.back().location.at;
313 bool operator!=(
const ExecutionPartIterator &other)
const {
314 return !(*
this == other);
317 ExecutionPartIterator &operator++() {
318 if (stepping_ == Step::Into) {
321 assert(stepping_ == Step::Over &&
"Unexpected stepping");
327 ExecutionPartIterator operator++(
int) {
328 ExecutionPartIterator copy{*
this};
333 using difference_type = IteratorType::difference_type;
334 using value_type = IteratorType::value_type;
335 using reference = IteratorType::reference;
336 using pointer = IteratorType::pointer;
337 using iterator_category = std::forward_iterator_tag;
340 IteratorType at()
const {
return stack_.back().location.at; };
346 const Step stepping_ = Step::Default;
347 std::vector<Construct> stack_;
350template <
typename Iterator = ExecutionPartIterator>
struct ExecutionPartRange {
351 using Step =
typename Iterator::Step;
353 ExecutionPartRange(Block::const_iterator begin, Block::const_iterator end,
354 Step stepping = Step::Default,
356 : begin_(begin, end, stepping, owner), end_() {}
357 template <
typename R,
typename = std::enable_if_t<is_range_v<R>>>
358 ExecutionPartRange(
const R &range, Step stepping = Step::Default,
360 : ExecutionPartRange(range.begin(), range.end(), stepping, owner) {}
362 Iterator begin()
const {
return begin_; }
363 Iterator end()
const {
return end_; }
366 Iterator begin_, end_;
369struct LoopNestIterator :
public ExecutionPartIterator {
370 LoopNestIterator() =
default;
372 LoopNestIterator(IteratorType b, IteratorType e, Step s = Step::Default,
374 : ExecutionPartIterator(b, e, s, c) {
377 template <
typename R,
typename = std::enable_if_t<is_range_v<R>>>
378 LoopNestIterator(
const R &range, Step stepping = Step::Default,
380 : LoopNestIterator(range.begin(), range.end(), stepping, construct) {}
382 LoopNestIterator &operator++() {
383 ExecutionPartIterator::operator++();
388 LoopNestIterator operator++(
int) {
389 LoopNestIterator copy{*
this};
398 while (valid() && !isLoop(**
this)) {
399 ExecutionPartIterator::operator++();
Definition indirection.h:31
Definition char-block.h:28
Definition parse-tree.h:439
Definition parse-tree.h:2325
Definition parse-tree.h:556
Definition parse-tree.h:5321
Definition parse-tree.h:5185
Definition parse-tree.h:3529
Definition parse-tree.h:5085
Definition parse-tree.h:3574
Definition parse-tree.h:5473
Definition parse-tree.h:5325
Definition parse-tree.h:5459
Definition parse-tree.h:5199
Definition parse-tree.h:3693
Definition openmp-utils.h:255
Definition openmp-utils.h:243
Definition openmp-utils.h:350
Definition openmp-utils.h:195
Definition openmp-utils.h:53
Definition openmp-utils.h:135
Definition openmp-utils.h:202