//===- ConstructDecompositionT.h -- Decomposing compound constructs -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Given a compound construct with a set of clauses, generate the list of // constituent leaf constructs, each with a list of clauses that apply to it. // // Note: Clauses that are not originally present, but that are implied by the // OpenMP spec are materialized, and are present in the output. // // Note: Composite constructs will also be broken up into leaf constructs. // If composite constructs require processing as a whole, the lists of clauses // for each leaf constituent should be merged. //===----------------------------------------------------------------------===// #ifndef LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H #define LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Frontend/OpenMP/ClauseT.h" #include "llvm/Frontend/OpenMP/OMP.h" #include <iterator> #include <list> #include <optional> #include <tuple> #include <type_traits> #include <unordered_map> #include <unordered_set> #include <utility> #include <variant> static inline llvm::ArrayRef<llvm::omp::Directive> getWorksharing() { … } static inline llvm::ArrayRef<llvm::omp::Directive> getWorksharingLoop() { … } namespace detail { template <typename Container, typename Predicate> typename std::remove_reference_t<Container>::iterator find_unique(Container &&container, Predicate &&pred) { … } } // namespace detail namespace tomp { // ClauseType - Either instance of ClauseT, or a type derived from ClauseT. // // This is the clause representation in the code using this infrastructure. // // HelperType - A class that implements two member functions: // // // Return the base object of the given object, if any. // std::optional<Object> getBaseObject(const Object &object) const // // Return the iteration variable of the outermost loop associated // // with the construct being worked on, if any. // std::optional<Object> getLoopIterVar() const template <typename ClauseType, typename HelperType> struct ConstructDecompositionT { … }; // Deduction guide template <typename ClauseType, typename HelperType> ConstructDecompositionT(uint32_t, HelperType &, llvm::omp::Directive, llvm::ArrayRef<ClauseType>) -> ConstructDecompositionT<ClauseType, HelperType>; template <typename C, typename H> void ConstructDecompositionT<C, H>::addClauseSymsToMap(const ObjectTy &object, const ClauseTy *node) { … } template <typename C, typename H> void ConstructDecompositionT<C, H>::addClauseSymsToMap( const tomp::ObjectListT<IdTy, ExprTy> &objects, const ClauseTy *node) { … } template <typename C, typename H> void ConstructDecompositionT<C, H>::addClauseSymsToMap(const TypeTy &item, const ClauseTy *node) { … } template <typename C, typename H> void ConstructDecompositionT<C, H>::addClauseSymsToMap(const ExprTy &item, const ClauseTy *node) { … } template <typename C, typename H> void ConstructDecompositionT<C, H>::addClauseSymsToMap( const tomp::clause::MapT<TypeTy, IdTy, ExprTy> &item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> void ConstructDecompositionT<C, H>::addClauseSymsToMap( const std::optional<U> &item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> void ConstructDecompositionT<C, H>::addClauseSymsToMap( const tomp::ListT<U> &item, const ClauseTy *node) { … } template <typename C, typename H> template <typename... U, size_t... Is> void ConstructDecompositionT<C, H>::addClauseSymsToMap( const std::tuple<U...> &item, const ClauseTy *node, std::index_sequence<Is...>) { … } template <typename C, typename H> template <typename U> std::enable_if_t<std::is_enum_v<llvm::remove_cvref_t<U>>, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> std::enable_if_t<llvm::remove_cvref_t<U>::EmptyTrait::value, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> std::enable_if_t<llvm::remove_cvref_t<U>::IncompleteTrait::value, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> std::enable_if_t<llvm::remove_cvref_t<U>::WrapperTrait::value, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> std::enable_if_t<llvm::remove_cvref_t<U>::TupleTrait::value, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } template <typename C, typename H> template <typename U> std::enable_if_t<llvm::remove_cvref_t<U>::UnionTrait::value, void> ConstructDecompositionT<C, H>::addClauseSymsToMap(U &&item, const ClauseTy *node) { … } // Apply a clause to the only directive that allows it. If there are no // directives that allow it, or if there is more that one, do not apply // anything and return false, otherwise return true. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyToUnique(const ClauseTy *node) { … } // Apply a clause to the first directive in given range that allows it. // If such a directive does not exist, return false, otherwise return true. template <typename C, typename H> template <typename Iterator> bool ConstructDecompositionT<C, H>::applyToFirst( const ClauseTy *node, llvm::iterator_range<Iterator> range) { … } // Apply a clause to the innermost directive that allows it. If such a // directive does not exist, return false, otherwise return true. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyToInnermost(const ClauseTy *node) { … } // Apply a clause to the outermost directive that allows it. If such a // directive does not exist, return false, otherwise return true. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyToOutermost(const ClauseTy *node) { … } template <typename C, typename H> template <typename Predicate> bool ConstructDecompositionT<C, H>::applyIf(const ClauseTy *node, Predicate shouldApply) { … } template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyToAll(const ClauseTy *node) { … } template <typename C, typename H> template <typename Specific> bool ConstructDecompositionT<C, H>::applyClause(Specific &&specific, const ClauseTy *node) { … } // COLLAPSE // [5.2:93:20-21] // Directives: distribute, do, for, loop, simd, taskloop // // [5.2:339:35] // (35) The collapse clause is applied once to the combined or composite // construct. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::CollapseT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // PRIVATE // [5.2:111:5-7] // Directives: distribute, do, for, loop, parallel, scope, sections, simd, // single, target, task, taskloop, teams // // [5.2:340:1-2] // (1) The effect of the 1 private clause is as if it is applied only to the // innermost leaf construct that permits it. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::PrivateT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // FIRSTPRIVATE // [5.2:112:5-7] // Directives: distribute, do, for, parallel, scope, sections, single, target, // task, taskloop, teams // // [5.2:340:3-20] // (3) The effect of the firstprivate clause is as if it is applied to one or // more leaf constructs as follows: // (5) To the distribute construct if it is among the constituent constructs; // (6) To the teams construct if it is among the constituent constructs and the // distribute construct is not; // (8) To a worksharing construct that accepts the clause if one is among the // constituent constructs; // (9) To the taskloop construct if it is among the constituent constructs; // (10) To the parallel construct if it is among the constituent constructs and // neither a taskloop construct nor a worksharing construct that accepts // the clause is among them; // (12) To the target construct if it is among the constituent constructs and // the same list item neither appears in a lastprivate clause nor is the // base variable or base pointer of a list item that appears in a map // clause. // // (15) If the parallel construct is among the constituent constructs and the // effect is not as if the firstprivate clause is applied to it by the above // rules, then the effect is as if the shared clause with the same list item is // applied to the parallel construct. // (17) If the teams construct is among the constituent constructs and the // effect is not as if the firstprivate clause is applied to it by the above // rules, then the effect is as if the shared clause with the same list item is // applied to the teams construct. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // LASTPRIVATE // [5.2:115:7-8] // Directives: distribute, do, for, loop, sections, simd, taskloop // // [5.2:340:21-30] // (21) The effect of the lastprivate clause is as if it is applied to all leaf // constructs that permit the clause. // (22) If the parallel construct is among the constituent constructs and the // list item is not also specified in the firstprivate clause, then the effect // of the lastprivate clause is as if the shared clause with the same list item // is applied to the parallel construct. // (24) If the teams construct is among the constituent constructs and the list // item is not also specified in the firstprivate clause, then the effect of the // lastprivate clause is as if the shared clause with the same list item is // applied to the teams construct. // (27) If the target construct is among the constituent constructs and the list // item is not the base variable or base pointer of a list item that appears in // a map clause, the effect of the lastprivate clause is as if the same list // item appears in a map clause with a map-type of tofrom. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // SHARED // [5.2:110:5-6] // Directives: parallel, task, taskloop, teams // // [5.2:340:31-32] // (31) The effect of the shared, default, thread_limit, or order clause is as // if it is applied to all leaf constructs that permit the clause. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::SharedT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // DEFAULT // [5.2:109:5-6] // Directives: parallel, task, taskloop, teams // // [5.2:340:31-32] // (31) The effect of the shared, default, thread_limit, or order clause is as // if it is applied to all leaf constructs that permit the clause. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::DefaultT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // THREAD_LIMIT // [5.2:277:14-15] // Directives: target, teams // // [5.2:340:31-32] // (31) The effect of the shared, default, thread_limit, or order clause is as // if it is applied to all leaf constructs that permit the clause. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // ORDER // [5.2:234:3-4] // Directives: distribute, do, for, loop, simd // // [5.2:340:31-32] // (31) The effect of the shared, default, thread_limit, or order clause is as // if it is applied to all leaf constructs that permit the clause. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::OrderT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // ALLOCATE // [5.2:178:7-9] // Directives: allocators, distribute, do, for, parallel, scope, sections, // single, target, task, taskgroup, taskloop, teams // // [5.2:340:33-35] // (33) The effect of the allocate clause is as if it is applied to all leaf // constructs that permit the clause and to which a data-sharing attribute // clause that may create a private copy of the same list item is applied. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::AllocateT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // REDUCTION // [5.2:134:17-18] // Directives: do, for, loop, parallel, scope, sections, simd, taskloop, teams // // [5.2:340:36-37], [5.2:341:1-13] // (36) The effect of the reduction clause is as if it is applied to all leaf // constructs that permit the clause, except for the following constructs: // (1) The parallel construct, when combined with the sections, // worksharing-loop, loop, or taskloop construct; and // (3) The teams construct, when combined with the loop construct. // (4) For the parallel and teams constructs above, the effect of the reduction // clause instead is as if each list item or, for any list item that is an array // item, its corresponding base array or base pointer appears in a shared clause // for the construct. // (6) If the task reduction-modifier is specified, the effect is as if it only // modifies the behavior of the reduction clause on the innermost leaf construct // that accepts the modifier (see Section 5.5.8). // (8) If the inscan reduction-modifier is specified, the effect is as if it // modifies the behavior of the reduction clause on all constructs of the // combined construct to which the clause is applied and that accept the // modifier. // (10) If a list item in a reduction clause on a combined target construct does // not have the same base variable or base pointer as a list item in a map // clause on the construct, then the effect is as if the list item in the // reduction clause appears as a list item in a map clause with a map-type of // tofrom. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::ReductionT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // IF // [5.2:72:7-9] // Directives: cancel, parallel, simd, target, target data, target enter data, // target exit data, target update, task, taskloop // // [5.2:72:15-18] // (15) For combined or composite constructs, the if clause only applies to the // semantics of the construct named in the directive-name-modifier. // (16) For a combined or composite construct, if no directive-name-modifier is // specified then the if clause applies to all constituent constructs to which // an if clause can apply. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::IfT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // LINEAR // [5.2:118:1-2] // Directives: declare simd, do, for, simd // // [5.2:341:15-22] // (15.1) The effect of the linear clause is as if it is applied to the // innermost leaf construct. // (15.2) Additionally, if the list item is not the iteration variable of a simd // or worksharing-loop SIMD construct, the effect on the outer leaf constructs // is as if the list item was specified in firstprivate and lastprivate clauses // on the combined or composite construct, with the rules specified above // applied. // (19) If a list item of the linear clause is the iteration variable of a simd // or worksharing-loop SIMD construct and it is not declared in the construct, // the effect on the outer leaf constructs is as if the list item was specified // in a lastprivate clause on the combined or composite construct with the rules // specified above applied. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::LinearT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } // NOWAIT // [5.2:308:11-13] // Directives: dispatch, do, for, interop, scope, sections, single, target, // target enter data, target exit data, target update, taskwait, workshare // // [5.2:341:23] // (23) The effect of the nowait clause is as if it is applied to the outermost // leaf construct that permits it. template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::NowaitT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } template <typename C, typename H> bool ConstructDecompositionT<C, H>::applyClause( const tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy> &clause, const ClauseTy *node) { … } template <typename C, typename H> bool ConstructDecompositionT<C, H>::split() { … } } // namespace tomp #endif // LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H