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