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