LLVM 24.0.0git
ConstructDecompositionT.h
Go to the documentation of this file.
1//===- ConstructDecompositionT.h -- Decomposing compound constructs -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// Given a compound construct with a set of clauses, generate the list of
9// constituent leaf constructs, each with a list of clauses that apply to it.
10//
11// Note: Clauses that are not originally present, but that are implied by the
12// OpenMP spec are materialized, and are present in the output.
13//
14// Note: Composite constructs will also be broken up into leaf constructs.
15// If composite constructs require processing as a whole, the lists of clauses
16// for each leaf constituent should be merged.
17//===----------------------------------------------------------------------===//
18#ifndef LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
19#define LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
20
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/STLExtras.h"
27
28#include <iterator>
29#include <list>
30#include <optional>
31#include <tuple>
32#include <type_traits>
33#include <unordered_map>
34#include <unordered_set>
35#include <utility>
36#include <variant>
37
39 static llvm::omp::Directive worksharing[] = {
40 llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_for,
41 llvm::omp::Directive::OMPD_scope, llvm::omp::Directive::OMPD_sections,
42 llvm::omp::Directive::OMPD_single, llvm::omp::Directive::OMPD_workshare,
43 };
44 return worksharing;
45}
46
48 static llvm::omp::Directive worksharingLoop[] = {
49 llvm::omp::Directive::OMPD_do,
50 llvm::omp::Directive::OMPD_for,
51 };
52 return worksharingLoop;
53}
54
55namespace detail {
56template <typename Container, typename Predicate>
57typename std::remove_reference_t<Container>::iterator
58find_unique(Container &&container, Predicate &&pred) {
59 auto first = llvm::find_if(container, pred);
60 if (first == container.end())
61 return first;
62 auto second = std::find_if(std::next(first), container.end(), pred);
63 if (second == container.end())
64 return first;
65 return container.end();
66}
67} // namespace detail
68
69namespace tomp {
70
71enum struct ErrorCode : int {
72 NoLeafAllowing, // No leaf that allows this clause
73 NoLeafPrivatizing, // No leaf that has a privatizing clause
74 InvalidDirNameMod, // Invalid directive name modifier
75 RedModNotApplied, // Reduction modifier not applied
76};
77
78// ClauseType: Either an instance of ClauseT, or a type derived from ClauseT.
79// This is the clause representation in the code using this infrastructure.
80//
81// HelperType: A class that implements 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
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 llvm::omp::Version 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(llvm::omp::Version, 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 // Match only a worksharing construct that accepts firstprivate; "workshare"
616 // does not, so it falls through to "parallel" per [5.2:340:10].
617 auto findWorksharingAcceptingFirstprivate = [&]() {
618 auto worksharing = getWorksharing();
619 for (auto &leaf : leafs) {
620 auto found = llvm::find(worksharing, leaf.id);
621 if (found != std::end(worksharing) &&
622 llvm::omp::isAllowedClauseForDirective(leaf.id, input->id, version))
623 return &leaf;
624 }
625 return static_cast<typename decltype(leafs)::value_type *>(nullptr);
626 };
627
628 auto dirWorksharing = findWorksharingAcceptingFirstprivate();
629 if (dirWorksharing != nullptr) {
630 dirWorksharing->clauses.push_back(input);
631 applied = true;
632 }
633
634 // [5.2:340:9]
635 auto dirTaskloop = findDirective(llvm::omp::OMPD_taskloop);
636 if (dirTaskloop != nullptr) {
637 dirTaskloop->clauses.push_back(input);
638 applied = true;
639 }
640
641 // [5.2:340:10]
642 auto dirParallel = findDirective(llvm::omp::OMPD_parallel);
643 if (dirParallel != nullptr) {
644 if (dirTaskloop == nullptr && dirWorksharing == nullptr) {
645 dirParallel->clauses.push_back(input);
646 applied = true;
647 } else {
648 // [5.2:340:15]
649 auto *shared = makeClause(
650 llvm::omp::Clause::OMPC_shared,
651 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/clause.v});
652 dirParallel->clauses.push_back(shared);
653 }
654 }
655
656 // [5.2:340:12]
657 auto inLastprivate = [&](const ObjectTy &object) {
658 if (ClauseSet *set = findClausesWith(object)) {
659 return llvm::find_if(*set, [](const ClauseTy *c) {
660 return c->id == llvm::omp::Clause::OMPC_lastprivate;
661 }) != set->end();
662 }
663 return false;
664 };
665
666 auto dirTarget = findDirective(llvm::omp::OMPD_target);
667 if (dirTarget != nullptr) {
670 clause.v, std::back_inserter(objects), [&](const ObjectTy &object) {
671 return !inLastprivate(object) && !mapBases.count(object.id());
672 });
673 if (!objects.empty()) {
674 auto *firstp = makeClause(
675 llvm::omp::Clause::OMPC_firstprivate,
676 tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{/*List=*/objects});
677 dirTarget->clauses.push_back(firstp);
678 applied = true;
679 }
680 }
681
682 // "task" is not handled by any of the cases above.
683 if (auto dirTask = findDirective(llvm::omp::OMPD_task)) {
684 dirTask->clauses.push_back(input);
685 applied = true;
686 }
687
688 if (!applied)
689 return error(input, ErrorCode::NoLeafAllowing);
690 return true;
691}
692
693// IF
694// [5.2:72:7-9]
695// Directives: cancel, parallel, simd, target, target data, target enter data,
696// target exit data, target update, task, taskloop
697//
698// [5.2:72:15-18]
699// (15) For combined or composite constructs, the if clause only applies to the
700// semantics of the construct named in the directive-name-modifier.
701// (16) For a combined or composite construct, if no directive-name-modifier is
702// specified then the if clause applies to all constituent constructs to which
703// an if clause can apply.
704template <typename C, typename H>
705bool ConstructDecompositionT<C, H>::applyClause(
706 const tomp::clause::IfT<TypeTy, IdTy, ExprTy> &clause,
707 const ClauseTy *input) {
710 using IfExpression = typename clause::IfT<TypeTy, IdTy, ExprTy>::IfExpression;
711 auto &modifier = std::get<std::optional<DirectiveNameModifier>>(clause.t);
712
713 if (modifier) {
714 llvm::omp::Directive dirId = *modifier;
715 auto *unmodified =
716 makeClause(llvm::omp::Clause::OMPC_if,
717 tomp::clause::IfT<TypeTy, IdTy, ExprTy>{
718 {/*DirectiveNameModifier=*/std::nullopt,
719 /*IfExpression=*/std::get<IfExpression>(clause.t)}});
720
721 if (auto *hasDir = findDirective(dirId)) {
722 hasDir->clauses.push_back(unmodified);
723 return true;
724 }
725 return error(input, ErrorCode::InvalidDirNameMod);
726 }
727
728 if (!applyToAll(input))
729 return error(input, ErrorCode::NoLeafAllowing);
730 return true;
731}
732
733// LASTPRIVATE
734// [5.2:115:7-8]
735// Directives: distribute, do, for, loop, sections, simd, taskloop
736//
737// [5.2:340:21-30]
738// (21) The effect of the lastprivate clause is as if it is applied to all leaf
739// constructs that permit the clause.
740// (22) If the parallel construct is among the constituent constructs and the
741// list item is not also specified in the firstprivate clause, then the effect
742// of the lastprivate clause is as if the shared clause with the same list item
743// is applied to the parallel construct.
744// (24) If the teams construct is among the constituent constructs and the list
745// item is not also specified in the firstprivate clause, then the effect of the
746// lastprivate clause is as if the shared clause with the same list item is
747// applied to the teams construct.
748// (27) If the target construct is among the constituent constructs and the list
749// item is not the base variable or base pointer of a list item that appears in
750// a map clause, the effect of the lastprivate clause is as if the same list
751// item appears in a map clause with a map-type of tofrom.
752template <typename C, typename H>
753bool ConstructDecompositionT<C, H>::applyClause(
754 const tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy> &clause,
755 const ClauseTy *input) {
756 // [5.2:340:21]
757 if (!applyToAll(input))
758 return error(input, ErrorCode::NoLeafAllowing);
759
760 auto inFirstprivate = [&](const ObjectTy &object) {
761 if (ClauseSet *set = findClausesWith(object)) {
762 return llvm::find_if(*set, [](const ClauseTy *c) {
763 return c->id == llvm::omp::Clause::OMPC_firstprivate;
764 }) != set->end();
765 }
766 return false;
767 };
768
769 auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
770
771 // Prepare list of objects that could end up in a "shared" clause.
774 objects, std::back_inserter(sharedObjects),
775 [&](const ObjectTy &object) { return !inFirstprivate(object); });
776
777 if (!sharedObjects.empty()) {
778 // [5.2:340:22]
779 if (auto dirParallel = findDirective(llvm::omp::OMPD_parallel)) {
780 auto *shared = makeClause(
781 llvm::omp::Clause::OMPC_shared,
782 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
783 dirParallel->clauses.push_back(shared);
784 }
785
786 // [5.2:340:24]
787 if (auto dirTeams = findDirective(llvm::omp::OMPD_teams)) {
788 auto *shared = makeClause(
789 llvm::omp::Clause::OMPC_shared,
790 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
791 dirTeams->clauses.push_back(shared);
792 }
793 }
794
795 // [5.2:340:27]
796 if (auto dirTarget = findDirective(llvm::omp::OMPD_target)) {
799 objects, std::back_inserter(tofrom),
800 [&](const ObjectTy &object) { return !mapBases.count(object.id()); });
801
802 if (!tofrom.empty()) {
803 using MapType =
804 typename tomp::clause::MapT<TypeTy, IdTy, ExprTy>::MapType;
805 auto *map =
806 makeClause(llvm::omp::Clause::OMPC_map,
807 tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
808 {/*MapType=*/MapType::Tofrom,
809 /*MapTypeModifier=*/std::nullopt,
810 /*AttachModifier=*/std::nullopt,
811 /*RefModifier=*/std::nullopt,
812 /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
813 /*LocatorList=*/std::move(tofrom)}});
814 dirTarget->clauses.push_back(map);
815 }
816 }
817
818 return true;
819}
820
821// LINEAR
822// [5.2:118:1-2]
823// Directives: declare simd, do, for, simd
824//
825// [5.2:341:15-22]
826// (15.1) The effect of the linear clause is as if it is applied to the
827// innermost leaf construct.
828// (15.2) Additionally, if the list item is not the iteration variable of a simd
829// or worksharing-loop SIMD construct, the effect on the outer leaf constructs
830// is as if the list item was specified in firstprivate and lastprivate clauses
831// on the combined or composite construct, with the rules specified above
832// applied.
833// (19) If a list item of the linear clause is the iteration variable of a simd
834// or worksharing-loop SIMD construct and it is not declared in the construct,
835// the effect on the outer leaf constructs is as if the list item was specified
836// in a lastprivate clause on the combined or composite construct with the rules
837// specified above applied.
838template <typename C, typename H>
839bool ConstructDecompositionT<C, H>::applyClause(
840 const tomp::clause::LinearT<TypeTy, IdTy, ExprTy> &clause,
841 const ClauseTy *input) {
842 // [5.2:341:15.1]
843 if (!applyToInnermost(input))
844 return error(input, ErrorCode::NoLeafAllowing);
845
846 // [5.2:341:15.2], [5.2:341:19]
847 auto dirSimd = findDirective(llvm::omp::Directive::OMPD_simd);
848 std::optional<ObjectTy> iterVar = helper.getLoopIterVar();
849 const auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
850
851 // Lists of objects that will be used to construct "firstprivate" and
852 // "lastprivate" clauses.
854
855 for (const ObjectTy &object : objects) {
856 last.push_back(object);
857 if (!dirSimd || !iterVar || object.id() != iterVar->id())
858 first.push_back(object);
859 }
860
861 if (!first.empty()) {
862 // A standalone "simd linear" may trigger the addition of "firstprivate",
863 // which will fail, since "simd" does not allow it. Add the firstprivate
864 // only if some leaf allows it.
865 bool allowed = llvm::any_of(leafs, [this](const LeafReprInternal &leaf) {
866 return llvm::omp::isAllowedClauseForDirective(
867 leaf.id, llvm::omp::Clause::OMPC_firstprivate, version);
868 });
869 if (allowed) {
870 auto *firstp = makeClause(
871 llvm::omp::Clause::OMPC_firstprivate,
872 tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{/*List=*/first});
873 inputClauses.push_back(firstp); // Appending to the main clause list.
874 }
875 }
876 if (!last.empty()) {
877 auto *lastp =
878 makeClause(llvm::omp::Clause::OMPC_lastprivate,
879 tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy>{
880 {/*LastprivateModifier=*/std::nullopt, /*List=*/last}});
881 inputClauses.push_back(lastp); // Appending to the main clause list.
882 }
883 return true;
884}
885
886// NOWAIT
887// [5.2:308:11-13]
888// Directives: dispatch, do, for, interop, scope, sections, single, target,
889// target enter data, target exit data, target update, taskwait, workshare
890//
891// [5.2:341:23]
892// (23) The effect of the nowait clause is as if it is applied to the outermost
893// leaf construct that permits it.
894template <typename C, typename H>
895bool ConstructDecompositionT<C, H>::applyClause(
896 const tomp::clause::NowaitT<TypeTy, IdTy, ExprTy> &clause,
897 const ClauseTy *input) {
898 if (!applyToOutermost(input))
899 return error(input, ErrorCode::NoLeafAllowing);
900 return true;
901}
902
903// OMPX_ATTRIBUTE
904template <typename C, typename H>
905bool ConstructDecompositionT<C, H>::applyClause(
906 const tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy> &clause,
907 const ClauseTy *input) {
908 if (!applyToAll(input))
909 return error(input, ErrorCode::NoLeafAllowing);
910 return true;
911}
912
913// OMPX_BARE
914template <typename C, typename H>
915bool ConstructDecompositionT<C, H>::applyClause(
916 const tomp::clause::OmpxBareT<TypeTy, IdTy, ExprTy> &clause,
917 const ClauseTy *input) {
918 if (!applyToOutermost(input))
919 return error(input, ErrorCode::NoLeafAllowing);
920 return true;
921}
922
923// ORDER
924// [5.2:234:3-4]
925// Directives: distribute, do, for, loop, simd
926//
927// [5.2:340:31-32]
928// (31) The effect of the shared, default, thread_limit, or order clause is as
929// if it is applied to all leaf constructs that permit the clause.
930template <typename C, typename H>
931bool ConstructDecompositionT<C, H>::applyClause(
932 const tomp::clause::OrderT<TypeTy, IdTy, ExprTy> &clause,
933 const ClauseTy *input) {
934 // [5.2:340:31]
935 if (!applyToAll(input))
936 return error(input, ErrorCode::NoLeafAllowing);
937 return true;
938}
939
940// PRIVATE
941// [5.2:111:5-7]
942// Directives: distribute, do, for, loop, parallel, scope, sections, simd,
943// single, target, task, taskloop, teams
944//
945// [5.2:340:1-2]
946// (1) The effect of the 1 private clause is as if it is applied only to the
947// innermost leaf construct that permits it.
948template <typename C, typename H>
949bool ConstructDecompositionT<C, H>::applyClause(
950 const tomp::clause::PrivateT<TypeTy, IdTy, ExprTy> &clause,
951 const ClauseTy *input) {
952 if (!applyToInnermost(input))
953 return error(input, ErrorCode::NoLeafAllowing);
954 return true;
955}
956
957// REDUCTION
958// [5.2:134:17-18]
959// Directives: do, for, loop, parallel, scope, sections, simd, taskloop, teams
960//
961// [5.2:340:36-37], [5.2:341:1-13]
962// (36) The effect of the reduction clause is as if it is applied to all leaf
963// constructs that permit the clause, except for the following constructs:
964// (1) The parallel construct, when combined with the sections,
965// worksharing-loop, loop, or taskloop construct; and
966// (3) The teams construct, when combined with the loop construct.
967// (4) For the parallel and teams constructs above, the effect of the reduction
968// clause instead is as if each list item or, for any list item that is an array
969// item, its corresponding base array or base pointer appears in a shared clause
970// for the construct.
971// (6) If the task reduction-modifier is specified, the effect is as if it only
972// modifies the behavior of the reduction clause on the innermost leaf construct
973// that accepts the modifier (see Section 5.5.8).
974// (8) If the inscan reduction-modifier is specified, the effect is as if it
975// modifies the behavior of the reduction clause on all constructs of the
976// combined construct to which the clause is applied and that accept the
977// modifier.
978// (10) If a list item in a reduction clause on a combined target construct does
979// not have the same base variable or base pointer as a list item in a map
980// clause on the construct, then the effect is as if the list item in the
981// reduction clause appears as a list item in a map clause with a map-type of
982// tofrom.
983template <typename C, typename H>
984bool ConstructDecompositionT<C, H>::applyClause(
985 const tomp::clause::ReductionT<TypeTy, IdTy, ExprTy> &clause,
986 const ClauseTy *input) {
987 using ReductionTy = tomp::clause::ReductionT<TypeTy, IdTy, ExprTy>;
988
989 // [5.2:340:36], [5.2:341:1], [5.2:341:3]
990 bool applyToParallel = true, applyToTeams = true;
991
992 auto dirParallel = findDirective(llvm::omp::Directive::OMPD_parallel);
993 if (dirParallel) {
996 llvm::omp::Directive::OMPD_loop,
997 llvm::omp::Directive::OMPD_sections,
998 llvm::omp::Directive::OMPD_taskloop,
999 });
1000 auto present = [&](llvm::omp::Directive id) {
1001 return findDirective(id) != nullptr;
1002 };
1003
1004 if (llvm::any_of(exclusions, present))
1005 applyToParallel = false;
1006 }
1007
1008 auto dirTeams = findDirective(llvm::omp::Directive::OMPD_teams);
1009 if (dirTeams) {
1010 // The only exclusion is OMPD_loop.
1011 if (findDirective(llvm::omp::Directive::OMPD_loop))
1012 applyToTeams = false;
1013 }
1014
1015 using ReductionModifier = typename ReductionTy::ReductionModifier;
1016 using ReductionIdentifiers = typename ReductionTy::ReductionIdentifiers;
1017
1018 auto &objects = std::get<tomp::ObjectListT<IdTy, ExprTy>>(clause.t);
1019 auto &modifier = std::get<std::optional<ReductionModifier>>(clause.t);
1020
1021 // Apply the reduction clause first to all directives according to the spec.
1022 // If the reduction was applied at least once, proceed with the data sharing
1023 // side-effects.
1024 bool applied = false;
1025
1026 // [5.2:341:6], [5.2:341:8]
1027 auto isValidModifier = [](llvm::omp::Directive dir, ReductionModifier mod,
1028 bool alreadyApplied) {
1029 switch (mod) {
1030 case ReductionModifier::Inscan:
1031 // According to [5.2:135:11-13], "inscan" only applies to
1032 // worksharing-loop, worksharing-loop-simd, or "simd" constructs.
1033 return dir == llvm::omp::Directive::OMPD_simd ||
1035 case ReductionModifier::Task:
1036 if (alreadyApplied) // Not an error
1037 return false;
1038 // According to [5.2:135:16-18], "task" only applies to "parallel" and
1039 // worksharing constructs.
1040 return dir == llvm::omp::Directive::OMPD_parallel ||
1042 case ReductionModifier::Default:
1043 return true;
1044 }
1045 llvm_unreachable("Unexpected modifier");
1046 };
1047
1048 auto *unmodified = makeClause(
1049 llvm::omp::Clause::OMPC_reduction,
1050 ReductionTy{
1051 {/*ReductionModifier=*/std::nullopt,
1052 /*ReductionIdentifiers=*/std::get<ReductionIdentifiers>(clause.t),
1053 /*List=*/objects}});
1054
1055 ReductionModifier effective = modifier.value_or(ReductionModifier::Default);
1056 bool modifierApplied = false;
1057 bool allowingLeaf = false;
1058 // Walk over the leaf constructs starting from the innermost, and apply
1059 // the clause as required by the spec.
1060 for (auto &leaf : llvm::reverse(leafs)) {
1061 if (!llvm::omp::isAllowedClauseForDirective(leaf.id, input->id, version))
1062 continue;
1063 // Found a leaf that allows this clause. Keep track of this for better
1064 // error reporting.
1065 allowingLeaf = true;
1066 if (!applyToParallel && &leaf == dirParallel)
1067 continue;
1068 if (!applyToTeams && &leaf == dirTeams)
1069 continue;
1070 // Some form of the clause will be applied past this point.
1071 if (isValidModifier(leaf.id, effective, modifierApplied)) {
1072 // Apply clause with modifier.
1073 leaf.clauses.push_back(input);
1074 modifierApplied = true;
1075 } else {
1076 // Apply clause without modifier.
1077 leaf.clauses.push_back(unmodified);
1078 }
1079 // The modifier must be applied to some construct.
1080 applied = modifierApplied;
1081 }
1082
1083 if (!allowingLeaf)
1084 return error(input, ErrorCode::NoLeafAllowing);
1085 if (!applied)
1086 return error(input, ErrorCode::RedModNotApplied);
1087
1088 tomp::ObjectListT<IdTy, ExprTy> sharedObjects;
1089 llvm::transform(objects, std::back_inserter(sharedObjects),
1090 [&](const ObjectTy &object) {
1091 auto maybeBase = helper.getBaseObject(object);
1092 return maybeBase ? *maybeBase : object;
1093 });
1094
1095 // [5.2:341:4]
1096 if (!sharedObjects.empty()) {
1097 if (dirParallel && !applyToParallel) {
1098 auto *shared = makeClause(
1099 llvm::omp::Clause::OMPC_shared,
1100 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
1101 dirParallel->clauses.push_back(shared);
1102 }
1103 if (dirTeams && !applyToTeams) {
1104 auto *shared = makeClause(
1105 llvm::omp::Clause::OMPC_shared,
1106 tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
1107 dirTeams->clauses.push_back(shared);
1108 }
1109 }
1110
1111 // [5.2:341:10]
1112 auto dirTarget = findDirective(llvm::omp::Directive::OMPD_target);
1113 if (dirTarget && leafs.size() > 1) {
1115 llvm::copy_if(objects, std::back_inserter(tofrom),
1116 [&](const ObjectTy &object) {
1117 if (auto maybeBase = helper.getBaseObject(object))
1118 return !mapBases.count(maybeBase->id());
1119 return !mapBases.count(object.id()); // XXX is this ok?
1120 });
1121 if (!tofrom.empty()) {
1122 using MapType =
1123 typename tomp::clause::MapT<TypeTy, IdTy, ExprTy>::MapType;
1124 auto *map = makeClause(
1125 llvm::omp::Clause::OMPC_map,
1126 tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
1127 {/*MapType=*/MapType::Tofrom, /*MapTypeModifier=*/std::nullopt,
1128 /*AttachModifier=*/std::nullopt, /*RefModifier=*/std::nullopt,
1129 /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
1130 /*LocatorList=*/std::move(tofrom)}});
1131
1132 dirTarget->clauses.push_back(map);
1133 }
1134 }
1135
1136 return true;
1137}
1138
1139// SHARED
1140// [5.2:110:5-6]
1141// Directives: parallel, task, taskloop, teams
1142//
1143// [5.2:340:31-32]
1144// (31) The effect of the shared, default, thread_limit, or order clause is as
1145// if it is applied to all leaf constructs that permit the clause.
1146template <typename C, typename H>
1147bool ConstructDecompositionT<C, H>::applyClause(
1148 const tomp::clause::SharedT<TypeTy, IdTy, ExprTy> &clause,
1149 const ClauseTy *input) {
1150 // [5.2:340:31]
1151 if (!applyToAll(input))
1152 return error(input, ErrorCode::NoLeafAllowing);
1153 return true;
1154}
1155
1156// THREAD_LIMIT
1157// [5.2:277:14-15]
1158// Directives: target, teams
1159//
1160// [5.2:340:31-32]
1161// (31) The effect of the shared, default, thread_limit, or order clause is as
1162// if it is applied to all leaf constructs that permit the clause.
1163template <typename C, typename H>
1164bool ConstructDecompositionT<C, H>::applyClause(
1165 const tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy> &clause,
1166 const ClauseTy *input) {
1167 // [5.2:340:31]
1168 if (!applyToAll(input))
1169 return error(input, ErrorCode::NoLeafAllowing);
1170 return true;
1171}
1172
1173// --- Splitting ------------------------------------------------------
1174
1175template <typename C, typename H> bool ConstructDecompositionT<C, H>::split() {
1176 bool success = true;
1177
1178 for (auto leaf : llvm::omp::getLeafConstructsOrSelf(inputDirective))
1179 leafs.push_back(LeafReprInternal{leaf, /*clauses=*/{}});
1180
1181 for (const ClauseTy *input : inputClauses)
1182 addClauseSymsToMap(*input, input);
1183
1184 // First we need to apply LINEAR, because it can generate additional
1185 // "firstprivate" and "lastprivate" clauses that apply to the combined/
1186 // composite construct.
1187 // Collect them separately, because they may modify the clause list.
1189 for (const ClauseTy *input : inputClauses) {
1190 if (input->id == llvm::omp::Clause::OMPC_linear)
1191 linears.push_back(input);
1192 }
1193 for (const auto *input : linears) {
1194 success = success &&
1195 applyClause(std::get<tomp::clause::LinearT<TypeTy, IdTy, ExprTy>>(
1196 input->u),
1197 input);
1198 }
1199
1200 // "allocate" clauses need to be applied last since they need to see
1201 // which directives have data-privatizing clauses.
1202 auto skip = [](const ClauseTy *input) {
1203 switch (input->id) {
1204 case llvm::omp::Clause::OMPC_allocate:
1205 case llvm::omp::Clause::OMPC_linear:
1206 return true;
1207 default:
1208 return false;
1209 }
1210 };
1211
1212 // Apply (almost) all clauses.
1213 for (const ClauseTy *input : inputClauses) {
1214 if (skip(input))
1215 continue;
1216 success =
1217 success &&
1218 std::visit([&](auto &&s) { return applyClause(s, input); }, input->u);
1219 }
1220
1221 // Apply "allocate".
1222 for (const ClauseTy *input : inputClauses) {
1223 if (input->id != llvm::omp::Clause::OMPC_allocate)
1224 continue;
1225 success =
1226 success &&
1227 std::visit([&](auto &&s) { return applyClause(s, input); }, input->u);
1228 }
1229
1230 return success;
1231}
1232
1233} // namespace tomp
1234
1235#endif // LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
static llvm::ArrayRef< llvm::omp::Directive > getWorksharing()
static llvm::ArrayRef< llvm::omp::Directive > getWorksharingLoop()
static bool shouldApply(Function &F, ProfileSummaryInfo &PSI)
static bool skip(GsymDataExtractor &Data, uint64_t &Offset, bool SkippedRanges)
Skip an InlineInfo object in the specified data at the specified offset.
SI Form memory clauses
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
#define error(X)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::remove_reference_t< Container >::iterator find_unique(Container &&container, Predicate &&pred)
LLVM_ABI ArrayRef< Directive > getLeafConstructsOrSelf(Directive D)
Definition OMP.cpp:106
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1765
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:2134
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:1791
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:2026
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:1746
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:1772
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
LogicalResult success(bool IsSuccess=true)
Utility function to generate a LogicalResult.
llvm::SmallVector< T, 0 > ListT
Definition ClauseT.h:150
ConstructDecompositionT(llvm::omp::Version, HelperType &, llvm::omp::Directive, llvm::ArrayRef< ClauseType >) -> ConstructDecompositionT< ClauseType, HelperType >
type::ObjectListT< I, E > ObjectListT
Definition ClauseT.h:316
type::ListT< T > ListT
Definition ClauseT.h:313
type::ObjectT< I, E > ObjectT
Definition ClauseT.h:315
llvm::SmallVector< std::pair< const ClauseType *, ErrorCode > > errors
std::unordered_set< const ClauseTy * > ClauseSet
ConstructDecompositionT(llvm::omp::Version ver, HelperType &helper, llvm::omp::Directive dir, llvm::ArrayRef< ClauseTy > clauses)
tomp::ObjectT< IdTy, ExprTy > ObjectTy
tomp::ListT< DirectiveWithClauses< ClauseType > > output
type::DirectiveName DirectiveNameModifier
Definition ClauseT.h:749
std::tuple< OPT(MapType), OPT(MapTypeModifiers), OPT(AttachModifier), OPT(RefModifier), OPT(Mappers), OPT(Iterator), LocatorList > t
Definition ClauseT.h:904