LLVM 24.0.0git
ConstructDecompositionT.h
Go to the documentation of this file.
1//===- ConstructDecompositionT.h -- Decomposing compound constructs -------===//
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// Given a compound construct with a set of clauses, generate the list of
9// constituent leaf constructs, each with a list of clauses that apply to it.
10//
11// Note: Clauses that are not originally present, but that are implied by the
12// OpenMP spec are materialized, and are present in the output.
13//
14// Note: Composite constructs will also be broken up into leaf constructs.
15// If composite constructs require processing as a whole, the lists of clauses
16// for each leaf constituent should be merged.
17//===----------------------------------------------------------------------===//
18#ifndef LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
19#define LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
20
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/STLExtras.h"
27
28#include <iterator>
29#include <list>
30#include <optional>
31#include <tuple>
32#include <type_traits>
33#include <unordered_map>
34#include <unordered_set>
35#include <utility>
36#include <variant>
37
39 static llvm::omp::Directive worksharing[] = {
40 llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_for,
41 llvm::omp::Directive::OMPD_scope, llvm::omp::Directive::OMPD_sections,
42 llvm::omp::Directive::OMPD_single, llvm::omp::Directive::OMPD_workshare,
43 };
44 return worksharing;
45}
46
48 static llvm::omp::Directive worksharingLoop[] = {
49 llvm::omp::Directive::OMPD_do,
50 llvm::omp::Directive::OMPD_for,
51 };
52 return worksharingLoop;
53}
54
55namespace detail {
56template <typename Container, typename Predicate>
57typename std::remove_reference_t<Container>::iterator
58find_unique(Container &&container, Predicate &&pred) {
59 auto first = llvm::find_if(container, pred);
60 if (first == container.end())
61 return first;
62 auto second = std::find_if(std::next(first), container.end(), pred);
63 if (second == container.end())
64 return first;
65 return container.end();
66}
67} // namespace detail
68
69namespace tomp {
70
71enum struct ErrorCode : int {
72 NoLeafAllowing, // No leaf that allows this clause
73 NoLeafPrivatizing, // No leaf that has a privatizing clause
74 InvalidDirNameMod, // Invalid directive name modifier
75 RedModNotApplied, // Reduction modifier not applied
76};
77
78// ClauseType: Either an instance of ClauseT, or a type derived from ClauseT.
79// This is the clause representation in the code using this infrastructure.
80//
81// HelperType: A class that implements three member functions:
82// // Return the base object of the given object, if any.
83// std::optional<Object> getBaseObject(const Object &object) const
84// // Return the iteration variable of the outermost loop associated
85// // with the construct being worked on, if any.
86// std::optional<Object> getLoopIterVar() const
87// // Is clause C allowed on directive D in version V.
88// bool isClauseAllowedOnDirective(Clause C, Directive D, Version V) const
89
90template <typename ClauseType, typename HelperType>
92 using ClauseTy = ClauseType;
93
94 using TypeTy = typename ClauseTy::TypeTy;
95 using IdTy = typename ClauseTy::IdTy;
96 using ExprTy = typename ClauseTy::ExprTy;
97 using HelperTy = HelperType;
99
100 using ClauseSet = std::unordered_set<const ClauseTy *>;
101
103 llvm::omp::Directive dir,
105 : version(ver), helper(helper), inputDirective(dir) {
106 for (const ClauseTy &clause : clauses)
107 inputClauses.push_back(&clause);
108
109 bool success = split();
110 if (!success)
111 return;
112
113 // Copy the individual leaf directives with their clauses to the
114 // output list. Copy by value, since we don't own the storage
115 // with the input clauses, and the internal representation uses
116 // clause addresses.
117 for (auto &leaf : leafs) {
118 output.push_back({leaf.id, {}});
119 auto &out = output.back();
120 for (const ClauseTy *c : leaf.clauses)
121 out.clauses.push_back(*c);
122 }
123 }
124
127
128private:
129 bool split();
130
131 bool error(const ClauseTy *input, ErrorCode ec) {
132 errors.emplace_back(input, ec);
133 return false;
134 }
135
136 struct LeafReprInternal {
137 llvm::omp::Directive id = llvm::omp::Directive::OMPD_unknown;
139 };
140
141 LeafReprInternal *findDirective(llvm::omp::Directive dirId) {
142 auto found = llvm::find_if(
143 leafs, [&](const LeafReprInternal &leaf) { return leaf.id == dirId; });
144 return found != leafs.end() ? &*found : nullptr;
145 }
146
147 ClauseSet *findClausesWith(const ObjectTy &object) {
148 if (auto found = syms.find(object.id()); found != syms.end())
149 return &found->second;
150 return nullptr;
151 }
152
153 template <typename S>
154 ClauseTy *makeClause(llvm::omp::Clause clauseId, S &&specific) {
155 implicit.push_back(typename ClauseTy::BaseT{clauseId, std::move(specific)});
156 return &implicit.back();
157 }
158
159 void addClauseSymsToMap(const ObjectTy &object, const ClauseTy *);
160 void addClauseSymsToMap(const tomp::ObjectListT<IdTy, ExprTy> &objects,
161 const ClauseTy *);
162 void addClauseSymsToMap(const TypeTy &item, const ClauseTy *);
163 void addClauseSymsToMap(const ExprTy &item, const ClauseTy *);
164 void addClauseSymsToMap(const tomp::clause::MapT<TypeTy, IdTy, ExprTy> &item,
165 const ClauseTy *);
166
167 template <typename U>
168 void addClauseSymsToMap(const std::optional<U> &item, const ClauseTy *);
169 template <typename U>
170 void addClauseSymsToMap(const tomp::ListT<U> &item, const ClauseTy *);
171 template <typename... U, size_t... Is>
172 void addClauseSymsToMap(const std::tuple<U...> &item, const ClauseTy *,
173 std::index_sequence<Is...> = {});
174 template <typename U>
175 std::enable_if_t<std::is_enum_v<llvm::remove_cvref_t<U>>, void>
176 addClauseSymsToMap(U &&item, const ClauseTy *);
177
178 template <typename U>
179 std::enable_if_t<llvm::remove_cvref_t<U>::EmptyTrait::value, void>
180 addClauseSymsToMap(U &&item, const ClauseTy *);
181
182 template <typename U>
183 std::enable_if_t<llvm::remove_cvref_t<U>::IncompleteTrait::value, void>
184 addClauseSymsToMap(U &&item, const ClauseTy *);
185
186 template <typename U>
187 std::enable_if_t<llvm::remove_cvref_t<U>::WrapperTrait::value, void>
188 addClauseSymsToMap(U &&item, const ClauseTy *);
189
190 template <typename U>
191 std::enable_if_t<llvm::remove_cvref_t<U>::TupleTrait::value, void>
192 addClauseSymsToMap(U &&item, const ClauseTy *);
193
194 template <typename U>
195 std::enable_if_t<llvm::remove_cvref_t<U>::UnionTrait::value, void>
196 addClauseSymsToMap(U &&item, const ClauseTy *);
197
198 // Apply the clause to the only directive that allows it. If there are no
199 // directives that allow it, or if there is more that one, do not apply
200 // anything and return false, otherwise return true.
201 bool applyToUnique(const ClauseTy *input);
202
203 // Apply the clause to the first directive in given range that allows it.
204 // If such a directive does not exist, return false, otherwise return true.
205 template <typename Iterator>
206 bool applyToFirst(const ClauseTy *input,
208
209 // Apply the clause to the innermost directive that allows it. If such a
210 // directive does not exist, return false, otherwise return true.
211 bool applyToInnermost(const ClauseTy *input);
212
213 // Apply the clause to the outermost directive that allows it. If such a
214 // directive does not exist, return false, otherwise return true.
215 bool applyToOutermost(const ClauseTy *input);
216
217 // Apply the clause to all directives that allow it, and which satisfy
218 // the predicate: bool shouldApply(LeafReprInternal). If no such
219 // directives exist, return false, otherwise return true.
220 template <typename Predicate>
221 bool applyIf(const ClauseTy *input, Predicate shouldApply);
222
223 // Apply the clause to all directives that allow it. If no such directives
224 // exist, return false, otherwise return true.
225 bool applyToAll(const ClauseTy *input);
226
227 template <typename Clause>
228 bool applyClause(Clause &&clause, const ClauseTy *input);
229
230 bool applyClause(const tomp::clause::AllocateT<TypeTy, IdTy, ExprTy> &clause,
231 const ClauseTy *);
232 bool applyClause(const tomp::clause::CollapseT<TypeTy, IdTy, ExprTy> &clause,
233 const ClauseTy *);
234 bool applyClause(const tomp::clause::DefaultT<TypeTy, IdTy, ExprTy> &clause,
235 const ClauseTy *);
236 bool applyClause(
237 const tomp::clause::DynGroupprivateT<TypeTy, IdTy, ExprTy> &clause,
238 const ClauseTy *);
239 bool
240 applyClause(const tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy> &clause,
241 const ClauseTy *);
242 bool applyClause(const tomp::clause::IfT<TypeTy, IdTy, ExprTy> &clause,
243 const ClauseTy *);
244 bool
245 applyClause(const tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy> &clause,
246 const ClauseTy *);
247 bool applyClause(const tomp::clause::LinearT<TypeTy, IdTy, ExprTy> &clause,
248 const ClauseTy *);
249 bool applyClause(const tomp::clause::NowaitT<TypeTy, IdTy, ExprTy> &clause,
250 const ClauseTy *);
251 bool
252 applyClause(const tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy> &clause,
253 const ClauseTy *);
254 bool applyClause(const tomp::clause::OmpxBareT<TypeTy, IdTy, ExprTy> &clause,
255 const ClauseTy *);
256 bool applyClause(const tomp::clause::OrderT<TypeTy, IdTy, ExprTy> &clause,
257 const ClauseTy *);
258 bool applyClause(const tomp::clause::PrivateT<TypeTy, IdTy, ExprTy> &clause,
259 const ClauseTy *);
260 bool applyClause(const tomp::clause::ReductionT<TypeTy, IdTy, ExprTy> &clause,
261 const ClauseTy *);
262 bool applyClause(const tomp::clause::SharedT<TypeTy, IdTy, ExprTy> &clause,
263 const ClauseTy *);
264 bool
265 applyClause(const tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy> &clause,
266 const ClauseTy *);
267
268 llvm::omp::Version version;
269 HelperType &helper;
270 llvm::omp::Directive inputDirective;
272
274 std::list<ClauseTy> implicit; // Container for materialized implicit clauses.
275 // Inserting must preserve element addresses.
276 std::unordered_map<IdTy, ClauseSet> syms;
277 std::unordered_set<IdTy> mapBases;
278};
279
280// Deduction guide
281template <typename ClauseType, typename HelperType>
282ConstructDecompositionT(llvm::omp::Version, HelperType &, llvm::omp::Directive,
285
286template <typename C, typename H>
287void ConstructDecompositionT<C, H>::addClauseSymsToMap(const ObjectTy &object,
288 const ClauseTy *input) {
289 syms[object.id()].insert(input);
290}
291
292template <typename C, typename H>
293void ConstructDecompositionT<C, H>::addClauseSymsToMap(
294 const tomp::ObjectListT<IdTy, ExprTy> &objects, const ClauseTy *input) {
295 for (auto &object : objects)
296 syms[object.id()].insert(input);
297}
298
299template <typename C, typename H>
300void ConstructDecompositionT<C, H>::addClauseSymsToMap(const TypeTy &item,
301 const ClauseTy *input) {
302 // Nothing to do for types.
303}
304
305template <typename C, typename H>
306void ConstructDecompositionT<C, H>::addClauseSymsToMap(const ExprTy &item,
307 const ClauseTy *input) {
308 // Nothing to do for expressions.
309}
310
311template <typename C, typename H>
312void ConstructDecompositionT<C, H>::addClauseSymsToMap(
313 const tomp::clause::MapT<TypeTy, IdTy, ExprTy> &item,
314 const ClauseTy *input) {
315 auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(item.t);
316 addClauseSymsToMap(objects, input);
317 for (auto &object : objects) {
318 if (auto base = helper.getBaseObject(object))
319 mapBases.insert(base->id());
320 }
321}
322
323template <typename C, typename H>
324template <typename U>
325void ConstructDecompositionT<C, H>::addClauseSymsToMap(
326 const std::optional<U> &item, const ClauseTy *input) {
327 if (item)
328 addClauseSymsToMap(*item, input);
329}
330
331template <typename C, typename H>
332template <typename U>
333void ConstructDecompositionT<C, H>::addClauseSymsToMap(
334 const tomp::ListT<U> &item, const ClauseTy *input) {
335 for (auto &s : item)
336 addClauseSymsToMap(s, input);
337}
338
339template <typename C, typename H>
340template <typename... U, size_t... Is>
341void ConstructDecompositionT<C, H>::addClauseSymsToMap(
342 const std::tuple<U...> &item, const ClauseTy *input,
343 std::index_sequence<Is...>) {
344 (void)input; // Silence strange warning from GCC.
345 (addClauseSymsToMap(std::get<Is>(item), input), ...);
346}
347
348template <typename C, typename H>
349template <typename U>
350std::enable_if_t<std::is_enum_v<llvm::remove_cvref_t<U>>, void>
351ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
352 const ClauseTy *input) {
353 // Nothing to do for enums.
354}
355
356template <typename C, typename H>
357template <typename U>
358std::enable_if_t<llvm::remove_cvref_t<U>::EmptyTrait::value, void>
359ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
360 const ClauseTy *input) {
361 // Nothing to do for an empty class.
362}
363
364template <typename C, typename H>
365template <typename U>
366std::enable_if_t<llvm::remove_cvref_t<U>::IncompleteTrait::value, void>
367ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
368 const ClauseTy *input) {
369 // Nothing to do for an incomplete class (they're empty).
370}
371
372template <typename C, typename H>
373template <typename U>
374std::enable_if_t<llvm::remove_cvref_t<U>::WrapperTrait::value, void>
375ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
376 const ClauseTy *input) {
377 addClauseSymsToMap(item.v, input);
378}
379
380template <typename C, typename H>
381template <typename U>
382std::enable_if_t<llvm::remove_cvref_t<U>::TupleTrait::value, void>
383ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
384 const ClauseTy *input) {
385 constexpr size_t tuple_size =
386 std::tuple_size_v<llvm::remove_cvref_t<decltype(item.t)>>;
387 addClauseSymsToMap(item.t, input, std::make_index_sequence<tuple_size>{});
388}
389
390template <typename C, typename H>
391template <typename U>
392std::enable_if_t<llvm::remove_cvref_t<U>::UnionTrait::value, void>
393ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item,
394 const ClauseTy *input) {
395 std::visit([&](auto &&s) { addClauseSymsToMap(s, input); }, item.u);
396}
397
398// Apply a clause to the only directive that allows it. If there are no
399// directives that allow it, or if there is more that one, do not apply
400// anything and return false, otherwise return true.
401template <typename C, typename H>
402bool ConstructDecompositionT<C, H>::applyToUnique(const ClauseTy *input) {
403 auto unique = ::detail::find_unique(leafs, [=](const auto &leaf) {
404 return helper.isClauseAllowedOnDirective(input->id, leaf.id, version);
405 });
406
407 if (unique != leafs.end()) {
408 unique->clauses.push_back(input);
409 return true;
410 }
411 return false;
412}
413
414// Apply a clause to the first directive in given range that allows it.
415// If such a directive does not exist, return false, otherwise return true.
416template <typename C, typename H>
417template <typename Iterator>
418bool ConstructDecompositionT<C, H>::applyToFirst(
419 const ClauseTy *input, llvm::iterator_range<Iterator> range) {
420 if (range.empty())
421 return false;
422
423 for (auto &leaf : range) {
424 if (!helper.isClauseAllowedOnDirective(input->id, leaf.id, version))
425 continue;
426 leaf.clauses.push_back(input);
427 return true;
428 }
429 return false;
430}
431
432// Apply a clause to the innermost directive that allows it. If such a
433// directive does not exist, return false, otherwise return true.
434template <typename C, typename H>
435bool ConstructDecompositionT<C, H>::applyToInnermost(const ClauseTy *input) {
436 return applyToFirst(input, llvm::reverse(leafs));
437}
438
439// Apply a clause to the outermost directive that allows it. If such a
440// directive does not exist, return false, otherwise return true.
441template <typename C, typename H>
442bool ConstructDecompositionT<C, H>::applyToOutermost(const ClauseTy *input) {
443 return applyToFirst(input, llvm::iterator_range(leafs));
444}
445
446template <typename C, typename H>
447template <typename Predicate>
448bool ConstructDecompositionT<C, H>::applyIf(const ClauseTy *input,
449 Predicate shouldApply) {
450 bool applied = false;
451 for (auto &leaf : leafs) {
452 if (!helper.isClauseAllowedOnDirective(input->id, leaf.id, version))
453 continue;
454 if (!shouldApply(leaf))
455 continue;
456 leaf.clauses.push_back(input);
457 applied = true;
458 }
459
460 return applied;
461}
462
463template <typename C, typename H>
464bool ConstructDecompositionT<C, H>::applyToAll(const ClauseTy *input) {
465 return applyIf(input, [](auto) { return true; });
466}
467
468template <typename C, typename H>
469template <typename Specific>
470bool ConstructDecompositionT<C, H>::applyClause(Specific &&specific,
471 const ClauseTy *input) {
472 // The default behavior is to find the unique directive to which the
473 // given clause may be applied. If there are no such directives, or
474 // if there are multiple ones, flag an error.
475 // From "OpenMP Application Programming Interface", Version 5.2:
476 // S Some clauses are permitted only on a single leaf construct of the
477 // S combined or composite construct, in which case the effect is as if
478 // S the clause is applied to that specific construct. (p339, 31-33)
479 if (!applyToUnique(input))
480 return error(input, ErrorCode::NoLeafAllowing);
481 return true;
482}
483
484// --- Specific clauses -----------------------------------------------
485
486// ALLOCATE
487// [5.2:178:7-9]
488// Directives: allocators, distribute, do, for, parallel, scope, sections,
489// single, target, task, taskgroup, taskloop, teams
490//
491// [5.2:340:33-35]
492// (33) The effect of the allocate clause is as if it is applied to all leaf
493// constructs that permit the clause and to which a data-sharing attribute
494// clause that may create a private copy of the same list item is applied.
495template <typename C, typename H>
496bool ConstructDecompositionT<C, H>::applyClause(
498 const ClauseTy *input) {
499 // This one needs to be applied at the end, once we know which clauses are
500 // assigned to which leaf constructs.
501
502 // [5.2:340:33]
503 bool applied = applyIf(input, [&](const auto &leaf) {
504 return llvm::any_of(leaf.clauses, [&](const ClauseTy *n) {
505 return llvm::omp::isPrivatizingClause(n->id, version);
506 });
507 });
508
509 if (!applied)
510 return error(input, ErrorCode::NoLeafPrivatizing);
511 return true;
512}
513
514// COLLAPSE
515// [5.2:93:20-21]
516// Directives: distribute, do, for, loop, simd, taskloop
517//
518// [5.2:339:35]
519// (35) The collapse clause is applied once to the combined or composite
520// construct.
521template <typename C, typename H>
522bool ConstructDecompositionT<C, H>::applyClause(
523 const tomp::clause::CollapseT<TypeTy, IdTy, ExprTy> &clause,
524 const ClauseTy *input) {
525 if (!applyToInnermost(input))
526 return error(input, ErrorCode::NoLeafAllowing);
527 return true;
528}
529
530// DEFAULT
531// [5.2:109:5-6]
532// Directives: parallel, task, taskloop, teams
533//
534// [5.2:340:31-32]
535// (31) The effect of the shared, default, thread_limit, or order clause is as
536// if it is applied to all leaf constructs that permit the clause.
537template <typename C, typename H>
538bool ConstructDecompositionT<C, H>::applyClause(
539 const tomp::clause::DefaultT<TypeTy, IdTy, ExprTy> &clause,
540 const ClauseTy *input) {
541 // [5.2:340:31]
542 if (!applyToAll(input))
543 return error(input, ErrorCode::NoLeafAllowing);
544 return true;
545}
546
547// DYN_GROUPPRIVATE
548// [6.1] dyn_groupprivate clause
549// Directives: target, teams
550//
551// The effect of the dyn_groupprivate clause is as if it is applied to the
552// outermost leaf construct that permits it.
553template <typename C, typename H>
554bool ConstructDecompositionT<C, H>::applyClause(
555 const tomp::clause::DynGroupprivateT<TypeTy, IdTy, ExprTy> &clause,
556 const ClauseTy *node) {
557 if (!applyToOutermost(node))
558 return error(node, ErrorCode::NoLeafAllowing);
559 return true;
560}
561
562// FIRSTPRIVATE
563// [5.2:112:5-7]
564// Directives: distribute, do, for, parallel, scope, sections, single, target,
565// task, taskloop, teams
566//
567// [5.2:340:3-20]
568// (3) The effect of the firstprivate clause is as if it is applied to one or
569// more leaf constructs as follows:
570// (5) To the distribute construct if it is among the constituent constructs;
571// (6) To the teams construct if it is among the constituent constructs and the
572// distribute construct is not;
573// (8) To a worksharing construct that accepts the clause if one is among the
574// constituent constructs;
575// (9) To the taskloop construct if it is among the constituent constructs;
576// (10) To the parallel construct if it is among the constituent constructs and
577// neither a taskloop construct nor a worksharing construct that accepts
578// the clause is among them;
579// (12) To the target construct if it is among the constituent constructs and
580// the same list item neither appears in a lastprivate clause nor is the
581// base variable or base pointer of a list item that appears in a map
582// clause.
583//
584// (15) If the parallel construct is among the constituent constructs and the
585// effect is not as if the firstprivate clause is applied to it by the above
586// rules, then the effect is as if the shared clause with the same list item is
587// applied to the parallel construct.
588// (17) If the teams construct is among the constituent constructs and the
589// effect is not as if the firstprivate clause is applied to it by the above
590// rules, then the effect is as if the shared clause with the same list item is
591// applied to the teams construct.
592template <typename C, typename H>
593bool ConstructDecompositionT<C, H>::applyClause(
594 const tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy> &clause,
595 const ClauseTy *input) {
596 bool applied = false;
597
598 // [5.2:340:3-6]
599 auto dirDistribute = findDirective(llvm::omp::OMPD_distribute);
600 auto dirTeams = findDirective(llvm::omp::OMPD_teams);
601 if (dirDistribute != nullptr) {
602 dirDistribute->clauses.push_back(input);
603 applied = true;
604 // [5.2:340:17]
605 if (dirTeams != nullptr) {
606 auto *shared = makeClause(
607 llvm::omp::Clause::OMPC_shared,
608 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/clause.v});
609 dirTeams->clauses.push_back(shared);
610 }
611 } else if (dirTeams != nullptr) {
612 dirTeams->clauses.push_back(input);
613 applied = true;
614 }
615
616 // [5.2:340:8]
617 // Match only a worksharing construct that accepts firstprivate; "workshare"
618 // does not, so it falls through to "parallel" per [5.2:340:10].
619 auto findWorksharingAcceptingFirstprivate = [&]() {
620 auto worksharing = getWorksharing();
621 for (auto &leaf : leafs) {
622 auto found = llvm::find(worksharing, leaf.id);
623 if (found != std::end(worksharing) &&
624 helper.isClauseAllowedOnDirective(input->id, leaf.id, version))
625 return &leaf;
626 }
627 return static_cast<typename decltype(leafs)::value_type *>(nullptr);
628 };
629
630 auto dirWorksharing = findWorksharingAcceptingFirstprivate();
631 if (dirWorksharing != nullptr) {
632 dirWorksharing->clauses.push_back(input);
633 applied = true;
634 }
635
636 // [5.2:340:9]
637 auto dirTaskloop = findDirective(llvm::omp::OMPD_taskloop);
638 if (dirTaskloop != nullptr) {
639 dirTaskloop->clauses.push_back(input);
640 applied = true;
641 }
642
643 // [5.2:340:10]
644 auto dirParallel = findDirective(llvm::omp::OMPD_parallel);
645 if (dirParallel != nullptr) {
646 if (dirTaskloop == nullptr && dirWorksharing == nullptr) {
647 dirParallel->clauses.push_back(input);
648 applied = true;
649 } else {
650 // [5.2:340:15]
651 auto *shared = makeClause(
652 llvm::omp::Clause::OMPC_shared,
653 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/clause.v});
654 dirParallel->clauses.push_back(shared);
655 }
656 }
657
658 // [5.2:340:12]
659 auto inLastprivate = [&](const ObjectTy &object) {
660 if (ClauseSet *set = findClausesWith(object)) {
661 return llvm::find_if(*set, [](const ClauseTy *c) {
662 return c->id == llvm::omp::Clause::OMPC_lastprivate;
663 }) != set->end();
664 }
665 return false;
666 };
667
668 auto dirTarget = findDirective(llvm::omp::OMPD_target);
669 if (dirTarget != nullptr) {
672 clause.v, std::back_inserter(objects), [&](const ObjectTy &object) {
673 return !inLastprivate(object) && !mapBases.count(object.id());
674 });
675 if (!objects.empty()) {
676 auto *firstp = makeClause(
677 llvm::omp::Clause::OMPC_firstprivate,
678 tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{/*List=*/objects});
679 dirTarget->clauses.push_back(firstp);
680 applied = true;
681 }
682 }
683
684 // "task" is not handled by any of the cases above.
685 if (auto dirTask = findDirective(llvm::omp::OMPD_task)) {
686 dirTask->clauses.push_back(input);
687 applied = true;
688 }
689
690 if (!applied)
691 return error(input, ErrorCode::NoLeafAllowing);
692 return true;
693}
694
695// IF
696// [5.2:72:7-9]
697// Directives: cancel, parallel, simd, target, target data, target enter data,
698// target exit data, target update, task, taskloop
699//
700// [5.2:72:15-18]
701// (15) For combined or composite constructs, the if clause only applies to the
702// semantics of the construct named in the directive-name-modifier.
703// (16) For a combined or composite construct, if no directive-name-modifier is
704// specified then the if clause applies to all constituent constructs to which
705// an if clause can apply.
706template <typename C, typename H>
707bool ConstructDecompositionT<C, H>::applyClause(
708 const tomp::clause::IfT<TypeTy, IdTy, ExprTy> &clause,
709 const ClauseTy *input) {
712 using IfExpression = typename clause::IfT<TypeTy, IdTy, ExprTy>::IfExpression;
713 auto &modifier = std::get<std::optional<DirectiveNameModifier>>(clause.t);
714
715 if (modifier) {
716 llvm::omp::Directive dirId = *modifier;
717 auto *unmodified =
718 makeClause(llvm::omp::Clause::OMPC_if,
719 tomp::clause::IfT<TypeTy, IdTy, ExprTy>{
720 {/*DirectiveNameModifier=*/std::nullopt,
721 /*IfExpression=*/std::get<IfExpression>(clause.t)}});
722
723 if (auto *hasDir = findDirective(dirId)) {
724 hasDir->clauses.push_back(unmodified);
725 return true;
726 }
727 return error(input, ErrorCode::InvalidDirNameMod);
728 }
729
730 if (!applyToAll(input))
731 return error(input, ErrorCode::NoLeafAllowing);
732 return true;
733}
734
735// LASTPRIVATE
736// [5.2:115:7-8]
737// Directives: distribute, do, for, loop, sections, simd, taskloop
738//
739// [5.2:340:21-30]
740// (21) The effect of the lastprivate clause is as if it is applied to all leaf
741// constructs that permit the clause.
742// (22) If the parallel construct is among the constituent constructs and the
743// list item is not also specified in the firstprivate clause, then the effect
744// of the lastprivate clause is as if the shared clause with the same list item
745// is applied to the parallel construct.
746// (24) If the teams construct is among the constituent constructs and the list
747// item is not also specified in the firstprivate clause, then the effect of the
748// lastprivate clause is as if the shared clause with the same list item is
749// applied to the teams construct.
750// (27) If the target construct is among the constituent constructs and the list
751// item is not the base variable or base pointer of a list item that appears in
752// a map clause, the effect of the lastprivate clause is as if the same list
753// item appears in a map clause with a map-type of tofrom.
754template <typename C, typename H>
755bool ConstructDecompositionT<C, H>::applyClause(
756 const tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy> &clause,
757 const ClauseTy *input) {
758 // [5.2:340:21]
759 if (!applyToAll(input))
760 return error(input, ErrorCode::NoLeafAllowing);
761
762 auto inFirstprivate = [&](const ObjectTy &object) {
763 if (ClauseSet *set = findClausesWith(object)) {
764 return llvm::find_if(*set, [](const ClauseTy *c) {
765 return c->id == llvm::omp::Clause::OMPC_firstprivate;
766 }) != set->end();
767 }
768 return false;
769 };
770
771 auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
772
773 // Prepare list of objects that could end up in a "shared" clause.
776 objects, std::back_inserter(sharedObjects),
777 [&](const ObjectTy &object) { return !inFirstprivate(object); });
778
779 if (!sharedObjects.empty()) {
780 // [5.2:340:22]
781 if (auto dirParallel = findDirective(llvm::omp::OMPD_parallel)) {
782 auto *shared = makeClause(
783 llvm::omp::Clause::OMPC_shared,
784 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
785 dirParallel->clauses.push_back(shared);
786 }
787
788 // [5.2:340:24]
789 if (auto dirTeams = findDirective(llvm::omp::OMPD_teams)) {
790 auto *shared = makeClause(
791 llvm::omp::Clause::OMPC_shared,
792 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
793 dirTeams->clauses.push_back(shared);
794 }
795 }
796
797 // [5.2:340:27]
798 if (auto dirTarget = findDirective(llvm::omp::OMPD_target)) {
801 objects, std::back_inserter(tofrom),
802 [&](const ObjectTy &object) { return !mapBases.count(object.id()); });
803
804 if (!tofrom.empty()) {
805 using MapType =
806 typename tomp::clause::MapT<TypeTy, IdTy, ExprTy>::MapType;
807 auto *map =
808 makeClause(llvm::omp::Clause::OMPC_map,
809 tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
810 {/*MapType=*/MapType::Tofrom,
811 /*MapTypeModifier=*/std::nullopt,
812 /*AttachModifier=*/std::nullopt,
813 /*RefModifier=*/std::nullopt,
814 /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
815 /*LocatorList=*/std::move(tofrom)}});
816 dirTarget->clauses.push_back(map);
817 }
818 }
819
820 return true;
821}
822
823// LINEAR
824// [5.2:118:1-2]
825// Directives: declare simd, do, for, simd
826//
827// [5.2:341:15-22]
828// (15.1) The effect of the linear clause is as if it is applied to the
829// innermost leaf construct.
830// (15.2) Additionally, if the list item is not the iteration variable of a simd
831// or worksharing-loop SIMD construct, the effect on the outer leaf constructs
832// is as if the list item was specified in firstprivate and lastprivate clauses
833// on the combined or composite construct, with the rules specified above
834// applied.
835// (19) If a list item of the linear clause is the iteration variable of a simd
836// or worksharing-loop SIMD construct and it is not declared in the construct,
837// the effect on the outer leaf constructs is as if the list item was specified
838// in a lastprivate clause on the combined or composite construct with the rules
839// specified above applied.
840template <typename C, typename H>
841bool ConstructDecompositionT<C, H>::applyClause(
842 const tomp::clause::LinearT<TypeTy, IdTy, ExprTy> &clause,
843 const ClauseTy *input) {
844 // [5.2:341:15.1]
845 if (!applyToInnermost(input))
846 return error(input, ErrorCode::NoLeafAllowing);
847
848 // [5.2:341:15.2], [5.2:341:19]
849 auto dirSimd = findDirective(llvm::omp::Directive::OMPD_simd);
850 std::optional<ObjectTy> iterVar = helper.getLoopIterVar();
851 const auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
852
853 // Lists of objects that will be used to construct "firstprivate" and
854 // "lastprivate" clauses.
856
857 for (const ObjectTy &object : objects) {
858 last.push_back(object);
859 if (!dirSimd || !iterVar || object.id() != iterVar->id())
860 first.push_back(object);
861 }
862
863 if (!first.empty()) {
864 // A standalone "simd linear" may trigger the addition of "firstprivate",
865 // which will fail, since "simd" does not allow it. Add the firstprivate
866 // only if some leaf allows it.
867 bool allowed = llvm::any_of(leafs, [this](const LeafReprInternal &leaf) {
868 return helper.isClauseAllowedOnDirective(
869 llvm::omp::Clause::OMPC_firstprivate, leaf.id, version);
870 });
871 if (allowed) {
872 auto *firstp = makeClause(
873 llvm::omp::Clause::OMPC_firstprivate,
874 tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{/*List=*/first});
875 inputClauses.push_back(firstp); // Appending to the main clause list.
876 }
877 }
878 if (!last.empty()) {
879 auto *lastp =
880 makeClause(llvm::omp::Clause::OMPC_lastprivate,
881 tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy>{
882 {/*LastprivateModifier=*/std::nullopt, /*List=*/last}});
883 inputClauses.push_back(lastp); // Appending to the main clause list.
884 }
885 return true;
886}
887
888// NOWAIT
889// [5.2:308:11-13]
890// Directives: dispatch, do, for, interop, scope, sections, single, target,
891// target enter data, target exit data, target update, taskwait, workshare
892//
893// [5.2:341:23]
894// (23) The effect of the nowait clause is as if it is applied to the outermost
895// leaf construct that permits it.
896template <typename C, typename H>
897bool ConstructDecompositionT<C, H>::applyClause(
898 const tomp::clause::NowaitT<TypeTy, IdTy, ExprTy> &clause,
899 const ClauseTy *input) {
900 if (!applyToOutermost(input))
901 return error(input, ErrorCode::NoLeafAllowing);
902 return true;
903}
904
905// OMPX_ATTRIBUTE
906template <typename C, typename H>
907bool ConstructDecompositionT<C, H>::applyClause(
908 const tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy> &clause,
909 const ClauseTy *input) {
910 if (!applyToAll(input))
911 return error(input, ErrorCode::NoLeafAllowing);
912 return true;
913}
914
915// OMPX_BARE
916template <typename C, typename H>
917bool ConstructDecompositionT<C, H>::applyClause(
918 const tomp::clause::OmpxBareT<TypeTy, IdTy, ExprTy> &clause,
919 const ClauseTy *input) {
920 if (!applyToOutermost(input))
921 return error(input, ErrorCode::NoLeafAllowing);
922 return true;
923}
924
925// ORDER
926// [5.2:234:3-4]
927// Directives: distribute, do, for, loop, simd
928//
929// [5.2:340:31-32]
930// (31) The effect of the shared, default, thread_limit, or order clause is as
931// if it is applied to all leaf constructs that permit the clause.
932template <typename C, typename H>
933bool ConstructDecompositionT<C, H>::applyClause(
934 const tomp::clause::OrderT<TypeTy, IdTy, ExprTy> &clause,
935 const ClauseTy *input) {
936 // [5.2:340:31]
937 if (!applyToAll(input))
938 return error(input, ErrorCode::NoLeafAllowing);
939 return true;
940}
941
942// PRIVATE
943// [5.2:111:5-7]
944// Directives: distribute, do, for, loop, parallel, scope, sections, simd,
945// single, target, task, taskloop, teams
946//
947// [5.2:340:1-2]
948// (1) The effect of the 1 private clause is as if it is applied only to the
949// innermost leaf construct that permits it.
950template <typename C, typename H>
951bool ConstructDecompositionT<C, H>::applyClause(
952 const tomp::clause::PrivateT<TypeTy, IdTy, ExprTy> &clause,
953 const ClauseTy *input) {
954 if (!applyToInnermost(input))
955 return error(input, ErrorCode::NoLeafAllowing);
956 return true;
957}
958
959// REDUCTION
960// [5.2:134:17-18]
961// Directives: do, for, loop, parallel, scope, sections, simd, taskloop, teams
962//
963// [5.2:340:36-37], [5.2:341:1-13]
964// (36) The effect of the reduction clause is as if it is applied to all leaf
965// constructs that permit the clause, except for the following constructs:
966// (1) The parallel construct, when combined with the sections,
967// worksharing-loop, loop, or taskloop construct; and
968// (3) The teams construct, when combined with the loop construct.
969// (4) For the parallel and teams constructs above, the effect of the reduction
970// clause instead is as if each list item or, for any list item that is an array
971// item, its corresponding base array or base pointer appears in a shared clause
972// for the construct.
973// (6) If the task reduction-modifier is specified, the effect is as if it only
974// modifies the behavior of the reduction clause on the innermost leaf construct
975// that accepts the modifier (see Section 5.5.8).
976// (8) If the inscan reduction-modifier is specified, the effect is as if it
977// modifies the behavior of the reduction clause on all constructs of the
978// combined construct to which the clause is applied and that accept the
979// modifier.
980// (10) If a list item in a reduction clause on a combined target construct does
981// not have the same base variable or base pointer as a list item in a map
982// clause on the construct, then the effect is as if the list item in the
983// reduction clause appears as a list item in a map clause with a map-type of
984// tofrom.
985template <typename C, typename H>
986bool ConstructDecompositionT<C, H>::applyClause(
987 const tomp::clause::ReductionT<TypeTy, IdTy, ExprTy> &clause,
988 const ClauseTy *input) {
989 using ReductionTy = tomp::clause::ReductionT<TypeTy, IdTy, ExprTy>;
990
991 // [5.2:340:36], [5.2:341:1], [5.2:341:3]
992 bool applyToParallel = true, applyToTeams = true;
993
994 auto dirParallel = findDirective(llvm::omp::Directive::OMPD_parallel);
995 if (dirParallel) {
998 llvm::omp::Directive::OMPD_loop,
999 llvm::omp::Directive::OMPD_sections,
1000 llvm::omp::Directive::OMPD_taskloop,
1001 });
1002 auto present = [&](llvm::omp::Directive id) {
1003 return findDirective(id) != nullptr;
1004 };
1005
1006 if (llvm::any_of(exclusions, present))
1007 applyToParallel = false;
1008 }
1009
1010 auto dirTeams = findDirective(llvm::omp::Directive::OMPD_teams);
1011 if (dirTeams) {
1012 // The only exclusion is OMPD_loop.
1013 if (findDirective(llvm::omp::Directive::OMPD_loop))
1014 applyToTeams = false;
1015 }
1016
1017 using ReductionModifier = typename ReductionTy::ReductionModifier;
1018 using ReductionIdentifiers = typename ReductionTy::ReductionIdentifiers;
1019
1020 auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
1021 auto &modifier = std::get<std::optional<ReductionModifier>>(clause.t);
1022
1023 // Apply the reduction clause first to all directives according to the spec.
1024 // If the reduction was applied at least once, proceed with the data sharing
1025 // side-effects.
1026 bool applied = false;
1027
1028 // [5.2:341:6], [5.2:341:8]
1029 auto isValidModifier = [](llvm::omp::Directive dir, ReductionModifier mod,
1030 bool alreadyApplied) {
1031 switch (mod) {
1032 case ReductionModifier::Inscan:
1033 // According to [5.2:135:11-13], "inscan" only applies to
1034 // worksharing-loop, worksharing-loop-simd, or "simd" constructs.
1035 return dir == llvm::omp::Directive::OMPD_simd ||
1037 case ReductionModifier::Task:
1038 if (alreadyApplied) // Not an error
1039 return false;
1040 // According to [5.2:135:16-18], "task" only applies to "parallel" and
1041 // worksharing constructs.
1042 return dir == llvm::omp::Directive::OMPD_parallel ||
1044 case ReductionModifier::Default:
1045 return true;
1046 }
1047 llvm_unreachable("Unexpected modifier");
1048 };
1049
1050 auto *unmodified = makeClause(
1051 llvm::omp::Clause::OMPC_reduction,
1052 ReductionTy{
1053 {/*ReductionModifier=*/std::nullopt,
1054 /*ReductionIdentifiers=*/std::get<ReductionIdentifiers>(clause.t),
1055 /*List=*/objects}});
1056
1057 ReductionModifier effective = modifier.value_or(ReductionModifier::Default);
1058 bool modifierApplied = false;
1059 bool allowingLeaf = false;
1060 // Walk over the leaf constructs starting from the innermost, and apply
1061 // the clause as required by the spec.
1062 for (auto &leaf : llvm::reverse(leafs)) {
1063 if (!helper.isClauseAllowedOnDirective(input->id, leaf.id, version))
1064 continue;
1065 // Found a leaf that allows this clause. Keep track of this for better
1066 // error reporting.
1067 allowingLeaf = true;
1068 if (!applyToParallel && &leaf == dirParallel)
1069 continue;
1070 if (!applyToTeams && &leaf == dirTeams)
1071 continue;
1072 // Some form of the clause will be applied past this point.
1073 if (isValidModifier(leaf.id, effective, modifierApplied)) {
1074 // Apply clause with modifier.
1075 leaf.clauses.push_back(input);
1076 modifierApplied = true;
1077 } else {
1078 // Apply clause without modifier.
1079 leaf.clauses.push_back(unmodified);
1080 }
1081 // The modifier must be applied to some construct.
1082 applied = modifierApplied;
1083 }
1084
1085 if (!allowingLeaf)
1086 return error(input, ErrorCode::NoLeafAllowing);
1087 if (!applied)
1088 return error(input, ErrorCode::RedModNotApplied);
1089
1090 tomp::ObjectListT<IdTy, ExprTy> sharedObjects;
1091 llvm::transform(objects, std::back_inserter(sharedObjects),
1092 [&](const ObjectTy &object) {
1093 auto maybeBase = helper.getBaseObject(object);
1094 return maybeBase ? *maybeBase : object;
1095 });
1096
1097 // [5.2:341:4]
1098 if (!sharedObjects.empty()) {
1099 if (dirParallel && !applyToParallel) {
1100 auto *shared = makeClause(
1101 llvm::omp::Clause::OMPC_shared,
1102 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
1103 dirParallel->clauses.push_back(shared);
1104 }
1105 if (dirTeams && !applyToTeams) {
1106 auto *shared = makeClause(
1107 llvm::omp::Clause::OMPC_shared,
1108 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
1109 dirTeams->clauses.push_back(shared);
1110 }
1111 }
1112
1113 // [5.2:341:10]
1114 auto dirTarget = findDirective(llvm::omp::Directive::OMPD_target);
1115 if (dirTarget && leafs.size() > 1) {
1117 llvm::copy_if(objects, std::back_inserter(tofrom),
1118 [&](const ObjectTy &object) {
1119 if (auto maybeBase = helper.getBaseObject(object))
1120 return !mapBases.count(maybeBase->id());
1121 return !mapBases.count(object.id()); // XXX is this ok?
1122 });
1123 if (!tofrom.empty()) {
1124 using MapType =
1125 typename tomp::clause::MapT<TypeTy, IdTy, ExprTy>::MapType;
1126 auto *map = makeClause(
1127 llvm::omp::Clause::OMPC_map,
1128 tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
1129 {/*MapType=*/MapType::Tofrom, /*MapTypeModifier=*/std::nullopt,
1130 /*AttachModifier=*/std::nullopt, /*RefModifier=*/std::nullopt,
1131 /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
1132 /*LocatorList=*/std::move(tofrom)}});
1133
1134 dirTarget->clauses.push_back(map);
1135 }
1136 }
1137
1138 return true;
1139}
1140
1141// SHARED
1142// [5.2:110:5-6]
1143// Directives: parallel, task, taskloop, teams
1144//
1145// [5.2:340:31-32]
1146// (31) The effect of the shared, default, thread_limit, or order clause is as
1147// if it is applied to all leaf constructs that permit the clause.
1148template <typename C, typename H>
1149bool ConstructDecompositionT<C, H>::applyClause(
1150 const tomp::clause::SharedT<TypeTy, IdTy, ExprTy> &clause,
1151 const ClauseTy *input) {
1152 // [5.2:340:31]
1153 if (!applyToAll(input))
1154 return error(input, ErrorCode::NoLeafAllowing);
1155 return true;
1156}
1157
1158// THREAD_LIMIT
1159// [5.2:277:14-15]
1160// Directives: target, teams
1161//
1162// [5.2:340:31-32]
1163// (31) The effect of the shared, default, thread_limit, or order clause is as
1164// if it is applied to all leaf constructs that permit the clause.
1165template <typename C, typename H>
1166bool ConstructDecompositionT<C, H>::applyClause(
1167 const tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy> &clause,
1168 const ClauseTy *input) {
1169 // [5.2:340:31]
1170 if (!applyToAll(input))
1171 return error(input, ErrorCode::NoLeafAllowing);
1172 return true;
1173}
1174
1175// --- Splitting ------------------------------------------------------
1176
1177template <typename C, typename H> bool ConstructDecompositionT<C, H>::split() {
1178 bool success = true;
1179
1180 for (auto leaf : llvm::omp::getLeafConstructsOrSelf(inputDirective))
1181 leafs.push_back(LeafReprInternal{leaf, /*clauses=*/{}});
1182
1183 for (const ClauseTy *input : inputClauses)
1184 addClauseSymsToMap(*input, input);
1185
1186 // First we need to apply LINEAR, because it can generate additional
1187 // "firstprivate" and "lastprivate" clauses that apply to the combined/
1188 // composite construct.
1189 // Collect them separately, because they may modify the clause list.
1191 for (const ClauseTy *input : inputClauses) {
1192 if (input->id == llvm::omp::Clause::OMPC_linear)
1193 linears.push_back(input);
1194 }
1195 for (const auto *input : linears) {
1196 success = success &&
1197 applyClause(std::get<tomp::clause::LinearT<TypeTy, IdTy, ExprTy>>(
1198 input->u),
1199 input);
1200 }
1201
1202 // "allocate" clauses need to be applied last since they need to see
1203 // which directives have data-privatizing clauses.
1204 auto skip = [](const ClauseTy *input) {
1205 switch (input->id) {
1206 case llvm::omp::Clause::OMPC_allocate:
1207 case llvm::omp::Clause::OMPC_linear:
1208 return true;
1209 default:
1210 return false;
1211 }
1212 };
1213
1214 // Apply (almost) all clauses.
1215 for (const ClauseTy *input : inputClauses) {
1216 if (skip(input))
1217 continue;
1218 success =
1219 success &&
1220 std::visit([&](auto &&s) { return applyClause(s, input); }, input->u);
1221 }
1222
1223 // Apply "allocate".
1224 for (const ClauseTy *input : inputClauses) {
1225 if (input->id != llvm::omp::Clause::OMPC_allocate)
1226 continue;
1227 success =
1228 success &&
1229 std::visit([&](auto &&s) { return applyClause(s, input); }, input->u);
1230 }
1231
1232 return success;
1233}
1234
1235} // namespace tomp
1236
1237#endif // LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
static llvm::ArrayRef< llvm::omp::Directive > getWorksharing()
static llvm::ArrayRef< llvm::omp::Directive > getWorksharingLoop()
static bool shouldApply(Function &F, ProfileSummaryInfo &PSI)
static bool skip(GsymDataExtractor &Data, uint64_t &Offset, bool SkippedRanges)
Skip an InlineInfo object in the specified data at the specified offset.
SI Form memory clauses
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
#define error(X)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::remove_reference_t< Container >::iterator find_unique(Container &&container, Predicate &&pred)
LLVM_ABI ArrayRef< Directive > getLeafConstructsOrSelf(Directive D)
Definition OMP.cpp:106
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1781
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt mod(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
is always non-negative.
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2150
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1807
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1167
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition STLExtras.h:2042
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
LogicalResult success(bool IsSuccess=true)
Utility function to generate a LogicalResult.
llvm::SmallVector< T, 0 > ListT
Definition ClauseT.h:150
ConstructDecompositionT(llvm::omp::Version, HelperType &, llvm::omp::Directive, llvm::ArrayRef< ClauseType >) -> ConstructDecompositionT< ClauseType, HelperType >
type::ObjectListT< I, E > ObjectListT
Definition ClauseT.h:316
type::ListT< T > ListT
Definition ClauseT.h:313
type::ObjectT< I, E > ObjectT
Definition ClauseT.h:315
llvm::SmallVector< std::pair< const ClauseType *, ErrorCode > > errors
std::unordered_set< const ClauseTy * > ClauseSet
ConstructDecompositionT(llvm::omp::Version ver, HelperType &helper, llvm::omp::Directive dir, llvm::ArrayRef< ClauseTy > clauses)
tomp::ObjectT< IdTy, ExprTy > ObjectTy
tomp::ListT< DirectiveWithClauses< ClauseType > > output
type::DirectiveName DirectiveNameModifier
Definition ClauseT.h:749
std::tuple< OPT(MapType), OPT(MapTypeModifiers), OPT(AttachModifier), OPT(RefModifier), OPT(Mappers), OPT(Iterator), LocatorList > t
Definition ClauseT.h:904