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