xref: /llvm-project/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp (revision 03cbe42627c7a7940b47cc1a2cda0120bc9c6d5e)
1be7c9e39SKrzysztof Parzyszek //===- llvm/unittests/Frontend/OpenMPDecompositionTest.cpp ----------------===//
2be7c9e39SKrzysztof Parzyszek //
3be7c9e39SKrzysztof Parzyszek // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4be7c9e39SKrzysztof Parzyszek // See https://llvm.org/LICENSE.txt for license information.
5be7c9e39SKrzysztof Parzyszek // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6be7c9e39SKrzysztof Parzyszek //
7be7c9e39SKrzysztof Parzyszek //===----------------------------------------------------------------------===//
8be7c9e39SKrzysztof Parzyszek 
9be7c9e39SKrzysztof Parzyszek #include "llvm/ADT/ArrayRef.h"
10be7c9e39SKrzysztof Parzyszek #include "llvm/ADT/STLExtras.h"
11be7c9e39SKrzysztof Parzyszek #include "llvm/ADT/SmallVector.h"
12be7c9e39SKrzysztof Parzyszek #include "llvm/Frontend/OpenMP/ClauseT.h"
13be7c9e39SKrzysztof Parzyszek #include "llvm/Frontend/OpenMP/ConstructDecompositionT.h"
14be7c9e39SKrzysztof Parzyszek #include "llvm/Frontend/OpenMP/OMP.h"
15be7c9e39SKrzysztof Parzyszek #include "gtest/gtest.h"
16be7c9e39SKrzysztof Parzyszek 
17be7c9e39SKrzysztof Parzyszek #include <iterator>
18be7c9e39SKrzysztof Parzyszek #include <optional>
19be7c9e39SKrzysztof Parzyszek #include <sstream>
20be7c9e39SKrzysztof Parzyszek #include <string>
21be7c9e39SKrzysztof Parzyszek #include <tuple>
22be7c9e39SKrzysztof Parzyszek #include <type_traits>
23be7c9e39SKrzysztof Parzyszek #include <utility>
24be7c9e39SKrzysztof Parzyszek 
25be7c9e39SKrzysztof Parzyszek // The actual tests start at comment "--- Test" below.
26be7c9e39SKrzysztof Parzyszek 
27be7c9e39SKrzysztof Parzyszek // Create simple instantiations of all clauses to allow manual construction
28be7c9e39SKrzysztof Parzyszek // of clauses, and implement emitting of a directive with clauses to a string.
29be7c9e39SKrzysztof Parzyszek //
30be7c9e39SKrzysztof Parzyszek // The tests then follow the pattern
31be7c9e39SKrzysztof Parzyszek // 1. Create a list of clauses.
32be7c9e39SKrzysztof Parzyszek // 2. Pass them, together with a construct, to the decomposition class.
33be7c9e39SKrzysztof Parzyszek // 3. Extract individual resulting leaf constructs with clauses applied
34be7c9e39SKrzysztof Parzyszek //    to them.
35be7c9e39SKrzysztof Parzyszek // 4. Convert them to strings and compare with expected outputs.
36be7c9e39SKrzysztof Parzyszek 
37be7c9e39SKrzysztof Parzyszek namespace omp {
38be7c9e39SKrzysztof Parzyszek struct TypeTy {}; // placeholder
39be7c9e39SKrzysztof Parzyszek struct ExprTy {}; // placeholder
40be7c9e39SKrzysztof Parzyszek using IdTy = std::string;
41be7c9e39SKrzysztof Parzyszek } // namespace omp
42be7c9e39SKrzysztof Parzyszek 
43be7c9e39SKrzysztof Parzyszek namespace tomp::type {
44be7c9e39SKrzysztof Parzyszek template <> struct ObjectT<omp::IdTy, omp::ExprTy> {
45be7c9e39SKrzysztof Parzyszek   const omp::IdTy &id() const { return name; }
46be7c9e39SKrzysztof Parzyszek   const std::optional<omp::ExprTy> ref() const { return omp::ExprTy{}; }
47be7c9e39SKrzysztof Parzyszek 
48be7c9e39SKrzysztof Parzyszek   omp::IdTy name;
49be7c9e39SKrzysztof Parzyszek };
50be7c9e39SKrzysztof Parzyszek } // namespace tomp::type
51be7c9e39SKrzysztof Parzyszek 
52be7c9e39SKrzysztof Parzyszek namespace omp {
53be7c9e39SKrzysztof Parzyszek template <typename ElemTy> using List = tomp::type::ListT<ElemTy>;
54be7c9e39SKrzysztof Parzyszek 
55be7c9e39SKrzysztof Parzyszek using Object = tomp::ObjectT<IdTy, ExprTy>;
56be7c9e39SKrzysztof Parzyszek 
57be7c9e39SKrzysztof Parzyszek namespace clause {
58be7c9e39SKrzysztof Parzyszek using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>;
59be7c9e39SKrzysztof Parzyszek using ProcedureDesignator = tomp::type::ProcedureDesignatorT<IdTy, ExprTy>;
60be7c9e39SKrzysztof Parzyszek using ReductionOperator = tomp::type::ReductionIdentifierT<IdTy, ExprTy>;
61be7c9e39SKrzysztof Parzyszek 
62be7c9e39SKrzysztof Parzyszek using AcqRel = tomp::clause::AcqRelT<TypeTy, IdTy, ExprTy>;
63be7c9e39SKrzysztof Parzyszek using Acquire = tomp::clause::AcquireT<TypeTy, IdTy, ExprTy>;
64be7c9e39SKrzysztof Parzyszek using AdjustArgs = tomp::clause::AdjustArgsT<TypeTy, IdTy, ExprTy>;
65be7c9e39SKrzysztof Parzyszek using Affinity = tomp::clause::AffinityT<TypeTy, IdTy, ExprTy>;
66be7c9e39SKrzysztof Parzyszek using Aligned = tomp::clause::AlignedT<TypeTy, IdTy, ExprTy>;
67be7c9e39SKrzysztof Parzyszek using Align = tomp::clause::AlignT<TypeTy, IdTy, ExprTy>;
68be7c9e39SKrzysztof Parzyszek using Allocate = tomp::clause::AllocateT<TypeTy, IdTy, ExprTy>;
69be7c9e39SKrzysztof Parzyszek using Allocator = tomp::clause::AllocatorT<TypeTy, IdTy, ExprTy>;
70be7c9e39SKrzysztof Parzyszek using AppendArgs = tomp::clause::AppendArgsT<TypeTy, IdTy, ExprTy>;
71be7c9e39SKrzysztof Parzyszek using AtomicDefaultMemOrder =
72be7c9e39SKrzysztof Parzyszek     tomp::clause::AtomicDefaultMemOrderT<TypeTy, IdTy, ExprTy>;
73be7c9e39SKrzysztof Parzyszek using At = tomp::clause::AtT<TypeTy, IdTy, ExprTy>;
74be7c9e39SKrzysztof Parzyszek using Bind = tomp::clause::BindT<TypeTy, IdTy, ExprTy>;
75be7c9e39SKrzysztof Parzyszek using Capture = tomp::clause::CaptureT<TypeTy, IdTy, ExprTy>;
76be7c9e39SKrzysztof Parzyszek using Collapse = tomp::clause::CollapseT<TypeTy, IdTy, ExprTy>;
77be7c9e39SKrzysztof Parzyszek using Compare = tomp::clause::CompareT<TypeTy, IdTy, ExprTy>;
78be7c9e39SKrzysztof Parzyszek using Copyin = tomp::clause::CopyinT<TypeTy, IdTy, ExprTy>;
79be7c9e39SKrzysztof Parzyszek using Copyprivate = tomp::clause::CopyprivateT<TypeTy, IdTy, ExprTy>;
80be7c9e39SKrzysztof Parzyszek using Defaultmap = tomp::clause::DefaultmapT<TypeTy, IdTy, ExprTy>;
81be7c9e39SKrzysztof Parzyszek using Default = tomp::clause::DefaultT<TypeTy, IdTy, ExprTy>;
82be7c9e39SKrzysztof Parzyszek using Depend = tomp::clause::DependT<TypeTy, IdTy, ExprTy>;
83be7c9e39SKrzysztof Parzyszek using Destroy = tomp::clause::DestroyT<TypeTy, IdTy, ExprTy>;
84be7c9e39SKrzysztof Parzyszek using Detach = tomp::clause::DetachT<TypeTy, IdTy, ExprTy>;
85be7c9e39SKrzysztof Parzyszek using Device = tomp::clause::DeviceT<TypeTy, IdTy, ExprTy>;
86be7c9e39SKrzysztof Parzyszek using DeviceType = tomp::clause::DeviceTypeT<TypeTy, IdTy, ExprTy>;
87be7c9e39SKrzysztof Parzyszek using DistSchedule = tomp::clause::DistScheduleT<TypeTy, IdTy, ExprTy>;
88be7c9e39SKrzysztof Parzyszek using Doacross = tomp::clause::DoacrossT<TypeTy, IdTy, ExprTy>;
89be7c9e39SKrzysztof Parzyszek using DynamicAllocators =
90be7c9e39SKrzysztof Parzyszek     tomp::clause::DynamicAllocatorsT<TypeTy, IdTy, ExprTy>;
91be7c9e39SKrzysztof Parzyszek using Enter = tomp::clause::EnterT<TypeTy, IdTy, ExprTy>;
92be7c9e39SKrzysztof Parzyszek using Exclusive = tomp::clause::ExclusiveT<TypeTy, IdTy, ExprTy>;
93be7c9e39SKrzysztof Parzyszek using Fail = tomp::clause::FailT<TypeTy, IdTy, ExprTy>;
94be7c9e39SKrzysztof Parzyszek using Filter = tomp::clause::FilterT<TypeTy, IdTy, ExprTy>;
95be7c9e39SKrzysztof Parzyszek using Final = tomp::clause::FinalT<TypeTy, IdTy, ExprTy>;
96be7c9e39SKrzysztof Parzyszek using Firstprivate = tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>;
97be7c9e39SKrzysztof Parzyszek using From = tomp::clause::FromT<TypeTy, IdTy, ExprTy>;
98be7c9e39SKrzysztof Parzyszek using Full = tomp::clause::FullT<TypeTy, IdTy, ExprTy>;
99be7c9e39SKrzysztof Parzyszek using Grainsize = tomp::clause::GrainsizeT<TypeTy, IdTy, ExprTy>;
100be7c9e39SKrzysztof Parzyszek using HasDeviceAddr = tomp::clause::HasDeviceAddrT<TypeTy, IdTy, ExprTy>;
101be7c9e39SKrzysztof Parzyszek using Hint = tomp::clause::HintT<TypeTy, IdTy, ExprTy>;
102be7c9e39SKrzysztof Parzyszek using If = tomp::clause::IfT<TypeTy, IdTy, ExprTy>;
103be7c9e39SKrzysztof Parzyszek using Inbranch = tomp::clause::InbranchT<TypeTy, IdTy, ExprTy>;
104be7c9e39SKrzysztof Parzyszek using Inclusive = tomp::clause::InclusiveT<TypeTy, IdTy, ExprTy>;
105be7c9e39SKrzysztof Parzyszek using Indirect = tomp::clause::IndirectT<TypeTy, IdTy, ExprTy>;
106be7c9e39SKrzysztof Parzyszek using Init = tomp::clause::InitT<TypeTy, IdTy, ExprTy>;
107be7c9e39SKrzysztof Parzyszek using InReduction = tomp::clause::InReductionT<TypeTy, IdTy, ExprTy>;
108be7c9e39SKrzysztof Parzyszek using IsDevicePtr = tomp::clause::IsDevicePtrT<TypeTy, IdTy, ExprTy>;
109be7c9e39SKrzysztof Parzyszek using Lastprivate = tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy>;
110be7c9e39SKrzysztof Parzyszek using Linear = tomp::clause::LinearT<TypeTy, IdTy, ExprTy>;
111be7c9e39SKrzysztof Parzyszek using Link = tomp::clause::LinkT<TypeTy, IdTy, ExprTy>;
112be7c9e39SKrzysztof Parzyszek using Map = tomp::clause::MapT<TypeTy, IdTy, ExprTy>;
113be7c9e39SKrzysztof Parzyszek using Match = tomp::clause::MatchT<TypeTy, IdTy, ExprTy>;
114be7c9e39SKrzysztof Parzyszek using Mergeable = tomp::clause::MergeableT<TypeTy, IdTy, ExprTy>;
115be7c9e39SKrzysztof Parzyszek using Message = tomp::clause::MessageT<TypeTy, IdTy, ExprTy>;
116be7c9e39SKrzysztof Parzyszek using Nocontext = tomp::clause::NocontextT<TypeTy, IdTy, ExprTy>;
117be7c9e39SKrzysztof Parzyszek using Nogroup = tomp::clause::NogroupT<TypeTy, IdTy, ExprTy>;
118be7c9e39SKrzysztof Parzyszek using Nontemporal = tomp::clause::NontemporalT<TypeTy, IdTy, ExprTy>;
119be7c9e39SKrzysztof Parzyszek using Notinbranch = tomp::clause::NotinbranchT<TypeTy, IdTy, ExprTy>;
120be7c9e39SKrzysztof Parzyszek using Novariants = tomp::clause::NovariantsT<TypeTy, IdTy, ExprTy>;
121be7c9e39SKrzysztof Parzyszek using Nowait = tomp::clause::NowaitT<TypeTy, IdTy, ExprTy>;
122be7c9e39SKrzysztof Parzyszek using NumTasks = tomp::clause::NumTasksT<TypeTy, IdTy, ExprTy>;
123be7c9e39SKrzysztof Parzyszek using NumTeams = tomp::clause::NumTeamsT<TypeTy, IdTy, ExprTy>;
124be7c9e39SKrzysztof Parzyszek using NumThreads = tomp::clause::NumThreadsT<TypeTy, IdTy, ExprTy>;
125be7c9e39SKrzysztof Parzyszek using OmpxAttribute = tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy>;
126be7c9e39SKrzysztof Parzyszek using OmpxBare = tomp::clause::OmpxBareT<TypeTy, IdTy, ExprTy>;
127be7c9e39SKrzysztof Parzyszek using OmpxDynCgroupMem = tomp::clause::OmpxDynCgroupMemT<TypeTy, IdTy, ExprTy>;
128be7c9e39SKrzysztof Parzyszek using Ordered = tomp::clause::OrderedT<TypeTy, IdTy, ExprTy>;
129be7c9e39SKrzysztof Parzyszek using Order = tomp::clause::OrderT<TypeTy, IdTy, ExprTy>;
130be7c9e39SKrzysztof Parzyszek using Partial = tomp::clause::PartialT<TypeTy, IdTy, ExprTy>;
131be7c9e39SKrzysztof Parzyszek using Priority = tomp::clause::PriorityT<TypeTy, IdTy, ExprTy>;
132be7c9e39SKrzysztof Parzyszek using Private = tomp::clause::PrivateT<TypeTy, IdTy, ExprTy>;
133be7c9e39SKrzysztof Parzyszek using ProcBind = tomp::clause::ProcBindT<TypeTy, IdTy, ExprTy>;
134be7c9e39SKrzysztof Parzyszek using Read = tomp::clause::ReadT<TypeTy, IdTy, ExprTy>;
135be7c9e39SKrzysztof Parzyszek using Reduction = tomp::clause::ReductionT<TypeTy, IdTy, ExprTy>;
136be7c9e39SKrzysztof Parzyszek using Relaxed = tomp::clause::RelaxedT<TypeTy, IdTy, ExprTy>;
137be7c9e39SKrzysztof Parzyszek using Release = tomp::clause::ReleaseT<TypeTy, IdTy, ExprTy>;
138be7c9e39SKrzysztof Parzyszek using ReverseOffload = tomp::clause::ReverseOffloadT<TypeTy, IdTy, ExprTy>;
139be7c9e39SKrzysztof Parzyszek using Safelen = tomp::clause::SafelenT<TypeTy, IdTy, ExprTy>;
140be7c9e39SKrzysztof Parzyszek using Schedule = tomp::clause::ScheduleT<TypeTy, IdTy, ExprTy>;
141be7c9e39SKrzysztof Parzyszek using SeqCst = tomp::clause::SeqCstT<TypeTy, IdTy, ExprTy>;
142be7c9e39SKrzysztof Parzyszek using Severity = tomp::clause::SeverityT<TypeTy, IdTy, ExprTy>;
143be7c9e39SKrzysztof Parzyszek using Shared = tomp::clause::SharedT<TypeTy, IdTy, ExprTy>;
144be7c9e39SKrzysztof Parzyszek using Simdlen = tomp::clause::SimdlenT<TypeTy, IdTy, ExprTy>;
145be7c9e39SKrzysztof Parzyszek using Simd = tomp::clause::SimdT<TypeTy, IdTy, ExprTy>;
146be7c9e39SKrzysztof Parzyszek using Sizes = tomp::clause::SizesT<TypeTy, IdTy, ExprTy>;
147be7c9e39SKrzysztof Parzyszek using TaskReduction = tomp::clause::TaskReductionT<TypeTy, IdTy, ExprTy>;
148be7c9e39SKrzysztof Parzyszek using ThreadLimit = tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy>;
149be7c9e39SKrzysztof Parzyszek using Threads = tomp::clause::ThreadsT<TypeTy, IdTy, ExprTy>;
150be7c9e39SKrzysztof Parzyszek using To = tomp::clause::ToT<TypeTy, IdTy, ExprTy>;
151be7c9e39SKrzysztof Parzyszek using UnifiedAddress = tomp::clause::UnifiedAddressT<TypeTy, IdTy, ExprTy>;
152be7c9e39SKrzysztof Parzyszek using UnifiedSharedMemory =
153be7c9e39SKrzysztof Parzyszek     tomp::clause::UnifiedSharedMemoryT<TypeTy, IdTy, ExprTy>;
154be7c9e39SKrzysztof Parzyszek using Uniform = tomp::clause::UniformT<TypeTy, IdTy, ExprTy>;
155be7c9e39SKrzysztof Parzyszek using Unknown = tomp::clause::UnknownT<TypeTy, IdTy, ExprTy>;
156be7c9e39SKrzysztof Parzyszek using Untied = tomp::clause::UntiedT<TypeTy, IdTy, ExprTy>;
157be7c9e39SKrzysztof Parzyszek using Update = tomp::clause::UpdateT<TypeTy, IdTy, ExprTy>;
158be7c9e39SKrzysztof Parzyszek using UseDeviceAddr = tomp::clause::UseDeviceAddrT<TypeTy, IdTy, ExprTy>;
159be7c9e39SKrzysztof Parzyszek using UseDevicePtr = tomp::clause::UseDevicePtrT<TypeTy, IdTy, ExprTy>;
160be7c9e39SKrzysztof Parzyszek using UsesAllocators = tomp::clause::UsesAllocatorsT<TypeTy, IdTy, ExprTy>;
161be7c9e39SKrzysztof Parzyszek using Use = tomp::clause::UseT<TypeTy, IdTy, ExprTy>;
162be7c9e39SKrzysztof Parzyszek using Weak = tomp::clause::WeakT<TypeTy, IdTy, ExprTy>;
163be7c9e39SKrzysztof Parzyszek using When = tomp::clause::WhenT<TypeTy, IdTy, ExprTy>;
164be7c9e39SKrzysztof Parzyszek using Write = tomp::clause::WriteT<TypeTy, IdTy, ExprTy>;
165be7c9e39SKrzysztof Parzyszek } // namespace clause
166be7c9e39SKrzysztof Parzyszek 
167be7c9e39SKrzysztof Parzyszek struct Helper {
168be7c9e39SKrzysztof Parzyszek   std::optional<Object> getBaseObject(const Object &object) {
169be7c9e39SKrzysztof Parzyszek     return std::nullopt;
170be7c9e39SKrzysztof Parzyszek   }
171be7c9e39SKrzysztof Parzyszek   std::optional<Object> getLoopIterVar() { return std::nullopt; }
172be7c9e39SKrzysztof Parzyszek };
173be7c9e39SKrzysztof Parzyszek 
174be7c9e39SKrzysztof Parzyszek using Clause = tomp::ClauseT<TypeTy, IdTy, ExprTy>;
175be7c9e39SKrzysztof Parzyszek using ConstructDecomposition = tomp::ConstructDecompositionT<Clause, Helper>;
176be7c9e39SKrzysztof Parzyszek using DirectiveWithClauses = tomp::DirectiveWithClauses<Clause>;
177be7c9e39SKrzysztof Parzyszek } // namespace omp
178be7c9e39SKrzysztof Parzyszek 
179be7c9e39SKrzysztof Parzyszek struct StringifyClause {
180be7c9e39SKrzysztof Parzyszek   static std::string join(const omp::List<std::string> &Strings) {
181be7c9e39SKrzysztof Parzyszek     std::stringstream Stream;
182be7c9e39SKrzysztof Parzyszek     for (const auto &[Index, String] : llvm::enumerate(Strings)) {
183be7c9e39SKrzysztof Parzyszek       if (Index != 0)
184be7c9e39SKrzysztof Parzyszek         Stream << ", ";
185be7c9e39SKrzysztof Parzyszek       Stream << String;
186be7c9e39SKrzysztof Parzyszek     }
187be7c9e39SKrzysztof Parzyszek     return Stream.str();
188be7c9e39SKrzysztof Parzyszek   }
189be7c9e39SKrzysztof Parzyszek 
190be7c9e39SKrzysztof Parzyszek   static std::string to_str(llvm::omp::Directive D) {
191be7c9e39SKrzysztof Parzyszek     return getOpenMPDirectiveName(D).str();
192be7c9e39SKrzysztof Parzyszek   }
193be7c9e39SKrzysztof Parzyszek   static std::string to_str(llvm::omp::Clause C) {
194be7c9e39SKrzysztof Parzyszek     return getOpenMPClauseName(C).str();
195be7c9e39SKrzysztof Parzyszek   }
196be7c9e39SKrzysztof Parzyszek   static std::string to_str(const omp::TypeTy &Type) { return "type"; }
197be7c9e39SKrzysztof Parzyszek   static std::string to_str(const omp::ExprTy &Expr) { return "expr"; }
198be7c9e39SKrzysztof Parzyszek   static std::string to_str(const omp::Object &Obj) { return Obj.id(); }
199be7c9e39SKrzysztof Parzyszek 
200be7c9e39SKrzysztof Parzyszek   template <typename U>
201be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<std::is_enum_v<llvm::remove_cvref_t<U>>, std::string>
202be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
203be7c9e39SKrzysztof Parzyszek     return std::to_string(llvm::to_underlying(Item));
204be7c9e39SKrzysztof Parzyszek   }
205be7c9e39SKrzysztof Parzyszek 
206be7c9e39SKrzysztof Parzyszek   template <typename U> static std::string to_str(const omp::List<U> &Items) {
207be7c9e39SKrzysztof Parzyszek     omp::List<std::string> Names;
208be7c9e39SKrzysztof Parzyszek     llvm::transform(Items, std::back_inserter(Names),
209be7c9e39SKrzysztof Parzyszek                     [](auto &&S) { return to_str(S); });
210be7c9e39SKrzysztof Parzyszek     return "(" + join(Names) + ")";
211be7c9e39SKrzysztof Parzyszek   }
212be7c9e39SKrzysztof Parzyszek 
213be7c9e39SKrzysztof Parzyszek   template <typename U>
214be7c9e39SKrzysztof Parzyszek   static std::string to_str(const std::optional<U> &Item) {
215be7c9e39SKrzysztof Parzyszek     if (Item)
216be7c9e39SKrzysztof Parzyszek       return to_str(*Item);
217be7c9e39SKrzysztof Parzyszek     return "";
218be7c9e39SKrzysztof Parzyszek   }
219be7c9e39SKrzysztof Parzyszek 
220be7c9e39SKrzysztof Parzyszek   template <typename... Us, size_t... Is>
221be7c9e39SKrzysztof Parzyszek   static std::string to_str(const std::tuple<Us...> &Tuple,
222be7c9e39SKrzysztof Parzyszek                             std::index_sequence<Is...>) {
223be7c9e39SKrzysztof Parzyszek     omp::List<std::string> Strings;
224be7c9e39SKrzysztof Parzyszek     (Strings.push_back(to_str(std::get<Is>(Tuple))), ...);
225be7c9e39SKrzysztof Parzyszek     return "(" + join(Strings) + ")";
226be7c9e39SKrzysztof Parzyszek   }
227be7c9e39SKrzysztof Parzyszek 
228be7c9e39SKrzysztof Parzyszek   template <typename U>
229be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<llvm::remove_cvref_t<U>::EmptyTrait::value,
230be7c9e39SKrzysztof Parzyszek                           std::string>
231be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
232be7c9e39SKrzysztof Parzyszek     return "";
233be7c9e39SKrzysztof Parzyszek   }
234be7c9e39SKrzysztof Parzyszek 
235be7c9e39SKrzysztof Parzyszek   template <typename U>
236be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<llvm::remove_cvref_t<U>::IncompleteTrait::value,
237be7c9e39SKrzysztof Parzyszek                           std::string>
238be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
239be7c9e39SKrzysztof Parzyszek     return "";
240be7c9e39SKrzysztof Parzyszek   }
241be7c9e39SKrzysztof Parzyszek 
242be7c9e39SKrzysztof Parzyszek   template <typename U>
243be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<llvm::remove_cvref_t<U>::WrapperTrait::value,
244be7c9e39SKrzysztof Parzyszek                           std::string>
245be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
246be7c9e39SKrzysztof Parzyszek     // For a wrapper, stringify the wrappee, and only add parentheses if
247be7c9e39SKrzysztof Parzyszek     // there aren't any already.
248be7c9e39SKrzysztof Parzyszek     std::string Str = to_str(Item.v);
249be7c9e39SKrzysztof Parzyszek     if (!Str.empty()) {
250be7c9e39SKrzysztof Parzyszek       if (Str.front() == '(' && Str.back() == ')')
251be7c9e39SKrzysztof Parzyszek         return Str;
252be7c9e39SKrzysztof Parzyszek     }
253be7c9e39SKrzysztof Parzyszek     return "(" + to_str(Item.v) + ")";
254be7c9e39SKrzysztof Parzyszek   }
255be7c9e39SKrzysztof Parzyszek 
256be7c9e39SKrzysztof Parzyszek   template <typename U>
257be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<llvm::remove_cvref_t<U>::TupleTrait::value,
258be7c9e39SKrzysztof Parzyszek                           std::string>
259be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
260be7c9e39SKrzysztof Parzyszek     constexpr size_t TupleSize =
261be7c9e39SKrzysztof Parzyszek         std::tuple_size_v<llvm::remove_cvref_t<decltype(Item.t)>>;
262be7c9e39SKrzysztof Parzyszek     return to_str(Item.t, std::make_index_sequence<TupleSize>{});
263be7c9e39SKrzysztof Parzyszek   }
264be7c9e39SKrzysztof Parzyszek 
265be7c9e39SKrzysztof Parzyszek   template <typename U>
266be7c9e39SKrzysztof Parzyszek   static std::enable_if_t<llvm::remove_cvref_t<U>::UnionTrait::value,
267be7c9e39SKrzysztof Parzyszek                           std::string>
268be7c9e39SKrzysztof Parzyszek   to_str(U &&Item) {
269be7c9e39SKrzysztof Parzyszek     return std::visit([](auto &&S) { return to_str(S); }, Item.u);
270be7c9e39SKrzysztof Parzyszek   }
271be7c9e39SKrzysztof Parzyszek 
272be7c9e39SKrzysztof Parzyszek   StringifyClause(const omp::Clause &C)
273be7c9e39SKrzysztof Parzyszek       // Rely on content stringification to emit enclosing parentheses.
274be7c9e39SKrzysztof Parzyszek       : Str(to_str(C.id) + to_str(C)) {}
275be7c9e39SKrzysztof Parzyszek 
276be7c9e39SKrzysztof Parzyszek   std::string Str;
277be7c9e39SKrzysztof Parzyszek };
278be7c9e39SKrzysztof Parzyszek 
279be7c9e39SKrzysztof Parzyszek std::string stringify(const omp::DirectiveWithClauses &DWC) {
280be7c9e39SKrzysztof Parzyszek   std::stringstream Stream;
281be7c9e39SKrzysztof Parzyszek 
282be7c9e39SKrzysztof Parzyszek   Stream << getOpenMPDirectiveName(DWC.id).str();
283be7c9e39SKrzysztof Parzyszek   for (const omp::Clause &C : DWC.clauses)
284be7c9e39SKrzysztof Parzyszek     Stream << ' ' << StringifyClause(C).Str;
285be7c9e39SKrzysztof Parzyszek 
286be7c9e39SKrzysztof Parzyszek   return Stream.str();
287be7c9e39SKrzysztof Parzyszek }
288be7c9e39SKrzysztof Parzyszek 
289be7c9e39SKrzysztof Parzyszek // --- Tests ----------------------------------------------------------
290be7c9e39SKrzysztof Parzyszek 
2914ec4a8e7SKrzysztof Parzyszek namespace red {
2924ec4a8e7SKrzysztof Parzyszek // Make it easier to construct reduction operators from built-in intrinsics.
2934ec4a8e7SKrzysztof Parzyszek omp::clause::ReductionOperator
2944ec4a8e7SKrzysztof Parzyszek makeOp(omp::clause::DefinedOperator::IntrinsicOperator Op) {
2954ec4a8e7SKrzysztof Parzyszek   return omp::clause::ReductionOperator{omp::clause::DefinedOperator{Op}};
2964ec4a8e7SKrzysztof Parzyszek }
2974ec4a8e7SKrzysztof Parzyszek } // namespace red
2984ec4a8e7SKrzysztof Parzyszek 
299be7c9e39SKrzysztof Parzyszek namespace {
300be7c9e39SKrzysztof Parzyszek using namespace llvm::omp;
301be7c9e39SKrzysztof Parzyszek 
302be7c9e39SKrzysztof Parzyszek class OpenMPDecompositionTest : public testing::Test {
303be7c9e39SKrzysztof Parzyszek protected:
304be7c9e39SKrzysztof Parzyszek   void SetUp() override {}
305be7c9e39SKrzysztof Parzyszek   void TearDown() override {}
306be7c9e39SKrzysztof Parzyszek 
307be7c9e39SKrzysztof Parzyszek   omp::Helper Helper;
308be7c9e39SKrzysztof Parzyszek   uint32_t AnyVersion = 999;
309be7c9e39SKrzysztof Parzyszek };
310be7c9e39SKrzysztof Parzyszek 
311be7c9e39SKrzysztof Parzyszek // PRIVATE
312be7c9e39SKrzysztof Parzyszek // [5.2:111:5-7]
313be7c9e39SKrzysztof Parzyszek // Directives: distribute, do, for, loop, parallel, scope, sections, simd,
314be7c9e39SKrzysztof Parzyszek // single, target, task, taskloop, teams
315be7c9e39SKrzysztof Parzyszek //
316be7c9e39SKrzysztof Parzyszek // [5.2:340:1-2]
317be7c9e39SKrzysztof Parzyszek // (1) The effect of the 1 private clause is as if it is applied only to the
318be7c9e39SKrzysztof Parzyszek // innermost leaf construct that permits it.
319be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Private1) {
320be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
321be7c9e39SKrzysztof Parzyszek 
322be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
323be7c9e39SKrzysztof Parzyszek       {OMPC_private, omp::clause::Private{{x}}},
324be7c9e39SKrzysztof Parzyszek   };
325be7c9e39SKrzysztof Parzyszek 
326be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
327be7c9e39SKrzysztof Parzyszek                                   Clauses);
328be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
329be7c9e39SKrzysztof Parzyszek 
330be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
331be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
332be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel");            // (1)
333be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections private(x)"); // (1)
334be7c9e39SKrzysztof Parzyszek }
335be7c9e39SKrzysztof Parzyszek 
336be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Private2) {
337be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
338be7c9e39SKrzysztof Parzyszek 
339be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
340be7c9e39SKrzysztof Parzyszek       {OMPC_private, omp::clause::Private{{x}}},
341be7c9e39SKrzysztof Parzyszek   };
342be7c9e39SKrzysztof Parzyszek 
343be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_masked,
344be7c9e39SKrzysztof Parzyszek                                   Clauses);
345be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
346be7c9e39SKrzysztof Parzyszek 
347be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
348be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
349be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel private(x)"); // (1)
350be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");              // (1)
351be7c9e39SKrzysztof Parzyszek }
352be7c9e39SKrzysztof Parzyszek 
353be7c9e39SKrzysztof Parzyszek // FIRSTPRIVATE
354be7c9e39SKrzysztof Parzyszek // [5.2:112:5-7]
355be7c9e39SKrzysztof Parzyszek // Directives: distribute, do, for, parallel, scope, sections, single, target,
356be7c9e39SKrzysztof Parzyszek // task, taskloop, teams
357be7c9e39SKrzysztof Parzyszek //
358be7c9e39SKrzysztof Parzyszek // [5.2:340:3-20]
359be7c9e39SKrzysztof Parzyszek // (3) The effect of the firstprivate clause is as if it is applied to one or
360be7c9e39SKrzysztof Parzyszek // more leaf constructs as follows:
361be7c9e39SKrzysztof Parzyszek //  (5) To the distribute construct if it is among the constituent constructs;
362be7c9e39SKrzysztof Parzyszek //  (6) To the teams construct if it is among the constituent constructs and the
363be7c9e39SKrzysztof Parzyszek //      distribute construct is not;
364be7c9e39SKrzysztof Parzyszek //  (8) To a worksharing construct that accepts the clause if one is among the
365be7c9e39SKrzysztof Parzyszek //      constituent constructs;
366be7c9e39SKrzysztof Parzyszek //  (9) To the taskloop construct if it is among the constituent constructs;
367be7c9e39SKrzysztof Parzyszek // (10) To the parallel construct if it is among the constituent constructs and
368be7c9e39SKrzysztof Parzyszek //      neither a taskloop construct nor a worksharing construct that accepts
369be7c9e39SKrzysztof Parzyszek //      the clause is among them;
370be7c9e39SKrzysztof Parzyszek // (12) To the target construct if it is among the constituent constructs and
371be7c9e39SKrzysztof Parzyszek //      the same list item neither appears in a lastprivate clause nor is the
372be7c9e39SKrzysztof Parzyszek //      base variable or base pointer of a list item that appears in a map
373be7c9e39SKrzysztof Parzyszek //      clause.
374be7c9e39SKrzysztof Parzyszek //
375be7c9e39SKrzysztof Parzyszek // (15) If the parallel construct is among the constituent constructs and the
376be7c9e39SKrzysztof Parzyszek // effect is not as if the firstprivate clause is applied to it by the above
377be7c9e39SKrzysztof Parzyszek // rules, then the effect is as if the shared clause with the same list item is
378be7c9e39SKrzysztof Parzyszek // applied to the parallel construct.
379be7c9e39SKrzysztof Parzyszek // (17) If the teams construct is among the constituent constructs and the
380be7c9e39SKrzysztof Parzyszek // effect is not as if the firstprivate clause is applied to it by the above
381be7c9e39SKrzysztof Parzyszek // rules, then the effect is as if the shared clause with the same list item is
382be7c9e39SKrzysztof Parzyszek // applied to the teams construct.
383be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate1) {
384be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
385be7c9e39SKrzysztof Parzyszek 
386be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
387be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
388be7c9e39SKrzysztof Parzyszek   };
389be7c9e39SKrzysztof Parzyszek 
390be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
391be7c9e39SKrzysztof Parzyszek                                   Clauses);
392be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
393be7c9e39SKrzysztof Parzyszek 
394be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
395be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
396be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");       // (10), (15)
397be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections firstprivate(x)"); // (8)
398be7c9e39SKrzysztof Parzyszek }
399be7c9e39SKrzysztof Parzyszek 
400be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate2) {
401be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
402be7c9e39SKrzysztof Parzyszek 
403be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
404be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
405be7c9e39SKrzysztof Parzyszek   };
406be7c9e39SKrzysztof Parzyszek 
407be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
408be7c9e39SKrzysztof Parzyszek                                   OMPD_target_teams_distribute, Clauses);
409be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
410be7c9e39SKrzysztof Parzyszek 
411be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
412be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
413be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
414be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target firstprivate(x)");     // (12)
415be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "teams shared(x)");            // (6), (17)
416be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "distribute firstprivate(x)"); // (5)
417be7c9e39SKrzysztof Parzyszek }
418be7c9e39SKrzysztof Parzyszek 
419be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate3) {
420be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
421be7c9e39SKrzysztof Parzyszek 
422be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
423be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
424be7c9e39SKrzysztof Parzyszek       {OMPC_lastprivate, omp::clause::Lastprivate{{std::nullopt, {x}}}},
425be7c9e39SKrzysztof Parzyszek   };
426be7c9e39SKrzysztof Parzyszek 
427be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
428be7c9e39SKrzysztof Parzyszek                                   OMPD_target_teams_distribute, Clauses);
429be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
430be7c9e39SKrzysztof Parzyszek 
431be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
432be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
433be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
434be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (12), (27)
435be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "teams shared(x)");          // (6), (17)
436be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "distribute firstprivate(x) lastprivate(, (x))"); // (5), (21)
437be7c9e39SKrzysztof Parzyszek }
438be7c9e39SKrzysztof Parzyszek 
439be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate4) {
440be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
441be7c9e39SKrzysztof Parzyszek 
442be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
443be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
444be7c9e39SKrzysztof Parzyszek   };
445be7c9e39SKrzysztof Parzyszek 
446be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_target_teams,
447be7c9e39SKrzysztof Parzyszek                                   Clauses);
448be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
449be7c9e39SKrzysztof Parzyszek 
450be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
451be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
452be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target firstprivate(x)"); // (12)
453be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "teams firstprivate(x)");  // (6)
454be7c9e39SKrzysztof Parzyszek }
455be7c9e39SKrzysztof Parzyszek 
456be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate5) {
457be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
458be7c9e39SKrzysztof Parzyszek 
459be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
460be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
461be7c9e39SKrzysztof Parzyszek   };
462be7c9e39SKrzysztof Parzyszek 
463be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
464be7c9e39SKrzysztof Parzyszek                                   OMPD_parallel_masked_taskloop, Clauses);
465be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
466be7c9e39SKrzysztof Parzyszek 
467be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
468be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
469be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
470be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)"); // (10)
471be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");
472be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "taskloop firstprivate(x)"); // (9)
473be7c9e39SKrzysztof Parzyszek }
474be7c9e39SKrzysztof Parzyszek 
475be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate6) {
476be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
477be7c9e39SKrzysztof Parzyszek 
478be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
479be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
480be7c9e39SKrzysztof Parzyszek   };
481be7c9e39SKrzysztof Parzyszek 
482be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_masked,
483be7c9e39SKrzysztof Parzyszek                                   Clauses);
484be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
485be7c9e39SKrzysztof Parzyszek 
486be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
487be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
488be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel firstprivate(x)"); // (10)
489be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");
490be7c9e39SKrzysztof Parzyszek }
491be7c9e39SKrzysztof Parzyszek 
492be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Firstprivate7) {
493be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
494be7c9e39SKrzysztof Parzyszek 
495be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
496be7c9e39SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
497be7c9e39SKrzysztof Parzyszek   };
498be7c9e39SKrzysztof Parzyszek 
499be7c9e39SKrzysztof Parzyszek   // Composite constructs are still decomposed.
500be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_teams_distribute,
501be7c9e39SKrzysztof Parzyszek                                   Clauses);
502be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
503be7c9e39SKrzysztof Parzyszek 
504be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
505be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
506be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams shared(x)");            // (17)
507be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "distribute firstprivate(x)"); // (5)
508be7c9e39SKrzysztof Parzyszek }
509be7c9e39SKrzysztof Parzyszek 
510be7c9e39SKrzysztof Parzyszek // LASTPRIVATE
511be7c9e39SKrzysztof Parzyszek // [5.2:115:7-8]
512be7c9e39SKrzysztof Parzyszek // Directives: distribute, do, for, loop, sections, simd, taskloop
513be7c9e39SKrzysztof Parzyszek //
514be7c9e39SKrzysztof Parzyszek // [5.2:340:21-30]
515be7c9e39SKrzysztof Parzyszek // (21) The effect of the lastprivate clause is as if it is applied to all leaf
516be7c9e39SKrzysztof Parzyszek // constructs that permit the clause.
517be7c9e39SKrzysztof Parzyszek // (22) If the parallel construct is among the constituent constructs and the
518be7c9e39SKrzysztof Parzyszek // list item is not also specified in the firstprivate clause, then the effect
519be7c9e39SKrzysztof Parzyszek // of the lastprivate clause is as if the shared clause with the same list item
520be7c9e39SKrzysztof Parzyszek // is applied to the parallel construct.
521be7c9e39SKrzysztof Parzyszek // (24) If the teams construct is among the constituent constructs and the list
522be7c9e39SKrzysztof Parzyszek // item is not also specified in the firstprivate clause, then the effect of the
523be7c9e39SKrzysztof Parzyszek // lastprivate clause is as if the shared clause with the same list item is
524be7c9e39SKrzysztof Parzyszek // applied to the teams construct.
525be7c9e39SKrzysztof Parzyszek // (27) If the target construct is among the constituent constructs and the list
526be7c9e39SKrzysztof Parzyszek // item is not the base variable or base pointer of a list item that appears in
527be7c9e39SKrzysztof Parzyszek // a map clause, the effect of the lastprivate clause is as if the same list
528be7c9e39SKrzysztof Parzyszek // item appears in a map clause with a map-type of tofrom.
529be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Lastprivate1) {
530be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
531be7c9e39SKrzysztof Parzyszek 
532be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
533be7c9e39SKrzysztof Parzyszek       {OMPC_lastprivate, omp::clause::Lastprivate{{std::nullopt, {x}}}},
534be7c9e39SKrzysztof Parzyszek   };
535be7c9e39SKrzysztof Parzyszek 
536be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
537be7c9e39SKrzysztof Parzyszek                                   Clauses);
538be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
539be7c9e39SKrzysztof Parzyszek 
540be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
541be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
542be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");          // (21), (22)
543be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections lastprivate(, (x))"); // (21)
544be7c9e39SKrzysztof Parzyszek }
545be7c9e39SKrzysztof Parzyszek 
546be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Lastprivate2) {
547be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
548be7c9e39SKrzysztof Parzyszek 
549be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
550be7c9e39SKrzysztof Parzyszek       {OMPC_lastprivate, omp::clause::Lastprivate{{std::nullopt, {x}}}},
551be7c9e39SKrzysztof Parzyszek   };
552be7c9e39SKrzysztof Parzyszek 
553be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_teams_distribute,
554be7c9e39SKrzysztof Parzyszek                                   Clauses);
555be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
556be7c9e39SKrzysztof Parzyszek 
557be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
558be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
559be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams shared(x)");               // (21), (25)
560be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "distribute lastprivate(, (x))"); // (21)
561be7c9e39SKrzysztof Parzyszek }
562be7c9e39SKrzysztof Parzyszek 
563be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Lastprivate3) {
564be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
565be7c9e39SKrzysztof Parzyszek 
566be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
567be7c9e39SKrzysztof Parzyszek       {OMPC_lastprivate, omp::clause::Lastprivate{{std::nullopt, {x}}}},
568be7c9e39SKrzysztof Parzyszek   };
569be7c9e39SKrzysztof Parzyszek 
570be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_target_parallel_do,
571be7c9e39SKrzysztof Parzyszek                                   Clauses);
572be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
573be7c9e39SKrzysztof Parzyszek 
574be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
575be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
576be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
577be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (21), (27)
578be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel shared(x)");       // (22)
579be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "do lastprivate(, (x))");    // (21)
580be7c9e39SKrzysztof Parzyszek }
581be7c9e39SKrzysztof Parzyszek 
582be7c9e39SKrzysztof Parzyszek // SHARED
583be7c9e39SKrzysztof Parzyszek // [5.2:110:5-6]
584be7c9e39SKrzysztof Parzyszek // Directives: parallel, task, taskloop, teams
585be7c9e39SKrzysztof Parzyszek //
586be7c9e39SKrzysztof Parzyszek // [5.2:340:31-32]
587be7c9e39SKrzysztof Parzyszek // (31) The effect of the shared, default, thread_limit, or order clause is as
588be7c9e39SKrzysztof Parzyszek // if it is applied to all leaf constructs that permit the clause.
589be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Shared1) {
590be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
591be7c9e39SKrzysztof Parzyszek 
592be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
593be7c9e39SKrzysztof Parzyszek       {OMPC_shared, omp::clause::Shared{{x}}},
594be7c9e39SKrzysztof Parzyszek   };
595be7c9e39SKrzysztof Parzyszek 
596be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
597be7c9e39SKrzysztof Parzyszek                                   OMPD_parallel_masked_taskloop, Clauses);
598be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
599be7c9e39SKrzysztof Parzyszek 
600be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
601be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
602be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
603be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)"); // (31)
604be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");             // (31)
605be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "taskloop shared(x)"); // (31)
606be7c9e39SKrzysztof Parzyszek }
607be7c9e39SKrzysztof Parzyszek 
608be7c9e39SKrzysztof Parzyszek // DEFAULT
609be7c9e39SKrzysztof Parzyszek // [5.2:109:5-6]
610be7c9e39SKrzysztof Parzyszek // Directives: parallel, task, taskloop, teams
611be7c9e39SKrzysztof Parzyszek //
612be7c9e39SKrzysztof Parzyszek // [5.2:340:31-32]
613be7c9e39SKrzysztof Parzyszek // (31) The effect of the shared, default, thread_limit, or order clause is as
614be7c9e39SKrzysztof Parzyszek // if it is applied to all leaf constructs that permit the clause.
615be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Default1) {
616be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
617be7c9e39SKrzysztof Parzyszek 
618be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
619be7c9e39SKrzysztof Parzyszek       {OMPC_default,
620be7c9e39SKrzysztof Parzyszek        omp::clause::Default{
621be7c9e39SKrzysztof Parzyszek            omp::clause::Default::DataSharingAttribute::Firstprivate}},
622be7c9e39SKrzysztof Parzyszek   };
623be7c9e39SKrzysztof Parzyszek 
624be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
625be7c9e39SKrzysztof Parzyszek                                   OMPD_parallel_masked_taskloop, Clauses);
626be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
627be7c9e39SKrzysztof Parzyszek 
628be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
629be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
630be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
631be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel default(0)"); // (31)
632be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");              // (31)
633be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "taskloop default(0)"); // (31)
634be7c9e39SKrzysztof Parzyszek }
635be7c9e39SKrzysztof Parzyszek 
636be7c9e39SKrzysztof Parzyszek // THREAD_LIMIT
637be7c9e39SKrzysztof Parzyszek // [5.2:277:14-15]
638be7c9e39SKrzysztof Parzyszek // Directives: target, teams
639be7c9e39SKrzysztof Parzyszek //
640be7c9e39SKrzysztof Parzyszek // [5.2:340:31-32]
641be7c9e39SKrzysztof Parzyszek // (31) The effect of the shared, default, thread_limit, or order clause is as
642be7c9e39SKrzysztof Parzyszek // if it is applied to all leaf constructs that permit the clause.
643be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, ThreadLimit1) {
644be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
645be7c9e39SKrzysztof Parzyszek 
646be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
647be7c9e39SKrzysztof Parzyszek       {OMPC_thread_limit, omp::clause::ThreadLimit{omp::ExprTy{}}},
648be7c9e39SKrzysztof Parzyszek   };
649be7c9e39SKrzysztof Parzyszek 
650be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
651be7c9e39SKrzysztof Parzyszek                                   OMPD_target_teams_distribute, Clauses);
652be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
653be7c9e39SKrzysztof Parzyszek 
654be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
655be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
656be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
657be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target thread_limit(expr)"); // (31)
658be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "teams thread_limit(expr)");  // (31)
659be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "distribute");                // (31)
660be7c9e39SKrzysztof Parzyszek }
661be7c9e39SKrzysztof Parzyszek 
662be7c9e39SKrzysztof Parzyszek // ORDER
663be7c9e39SKrzysztof Parzyszek // [5.2:234:3-4]
664be7c9e39SKrzysztof Parzyszek // Directives: distribute, do, for, loop, simd
665be7c9e39SKrzysztof Parzyszek //
666be7c9e39SKrzysztof Parzyszek // [5.2:340:31-32]
667be7c9e39SKrzysztof Parzyszek // (31) The effect of the shared, default, thread_limit, or order clause is as
668be7c9e39SKrzysztof Parzyszek // if it is applied to all leaf constructs that permit the clause.
669be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Order1) {
670be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
671be7c9e39SKrzysztof Parzyszek 
672be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
673be7c9e39SKrzysztof Parzyszek       {OMPC_order,
674be7c9e39SKrzysztof Parzyszek        omp::clause::Order{{omp::clause::Order::OrderModifier::Unconstrained,
675be7c9e39SKrzysztof Parzyszek                            omp::clause::Order::Ordering::Concurrent}}},
676be7c9e39SKrzysztof Parzyszek   };
677be7c9e39SKrzysztof Parzyszek 
678be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(
679be7c9e39SKrzysztof Parzyszek       AnyVersion, Helper, OMPD_target_teams_distribute_parallel_for_simd,
680be7c9e39SKrzysztof Parzyszek       Clauses);
681be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 6u);
682be7c9e39SKrzysztof Parzyszek 
683be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
684be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
685be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
686be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
687be7c9e39SKrzysztof Parzyszek   std::string Dir4 = stringify(Dec.output[4]);
688be7c9e39SKrzysztof Parzyszek   std::string Dir5 = stringify(Dec.output[5]);
689be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target");                 // (31)
690be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "teams");                  // (31)
691b4ab52c8Sharishch4   ASSERT_EQ(Dir2, "distribute order(1, 0)"); // (31)
692be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "parallel");               // (31)
693be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir4, "for order(1, 0)");        // (31)
694be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir5, "simd order(1, 0)");       // (31)
695be7c9e39SKrzysztof Parzyszek }
696be7c9e39SKrzysztof Parzyszek 
697be7c9e39SKrzysztof Parzyszek // ALLOCATE
698be7c9e39SKrzysztof Parzyszek // [5.2:178:7-9]
699be7c9e39SKrzysztof Parzyszek // Directives: allocators, distribute, do, for, parallel, scope, sections,
700be7c9e39SKrzysztof Parzyszek // single, target, task, taskgroup, taskloop, teams
701be7c9e39SKrzysztof Parzyszek //
702be7c9e39SKrzysztof Parzyszek // [5.2:340:33-35]
703be7c9e39SKrzysztof Parzyszek // (33) The effect of the allocate clause is as if it is applied to all leaf
704be7c9e39SKrzysztof Parzyszek // constructs that permit the clause and to which a data-sharing attribute
705be7c9e39SKrzysztof Parzyszek // clause that may create a private copy of the same list item is applied.
706be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate1) {
707be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
708be7c9e39SKrzysztof Parzyszek 
7094ec4a8e7SKrzysztof Parzyszek   // Allocate + firstprivate
7104ec4a8e7SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
711cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
7124ec4a8e7SKrzysztof Parzyszek       {OMPC_firstprivate, omp::clause::Firstprivate{{x}}},
7134ec4a8e7SKrzysztof Parzyszek   };
7144ec4a8e7SKrzysztof Parzyszek 
7154ec4a8e7SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
7164ec4a8e7SKrzysztof Parzyszek                                   Clauses);
7174ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
7184ec4a8e7SKrzysztof Parzyszek 
7194ec4a8e7SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
7204ec4a8e7SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
7214ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");                         // (33)
722cdbd2287SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections firstprivate(x) allocate(, , (x))"); // (33)
7234ec4a8e7SKrzysztof Parzyszek }
7244ec4a8e7SKrzysztof Parzyszek 
7254ec4a8e7SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate2) {
7264ec4a8e7SKrzysztof Parzyszek   omp::Object x{"x"};
7274ec4a8e7SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
7284ec4a8e7SKrzysztof Parzyszek 
7294ec4a8e7SKrzysztof Parzyszek   // Allocate + in_reduction
7304ec4a8e7SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
731cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
7324ec4a8e7SKrzysztof Parzyszek       {OMPC_in_reduction, omp::clause::InReduction{{{Add}, {x}}}},
7334ec4a8e7SKrzysztof Parzyszek   };
7344ec4a8e7SKrzysztof Parzyszek 
7354ec4a8e7SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_target_parallel,
7364ec4a8e7SKrzysztof Parzyszek                                   Clauses);
7374ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
7384ec4a8e7SKrzysztof Parzyszek 
7394ec4a8e7SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
7404ec4a8e7SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
741cdbd2287SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target in_reduction((3), (x)) allocate(, , (x))"); // (33)
7424ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel");                                        // (33)
7434ec4a8e7SKrzysztof Parzyszek }
7444ec4a8e7SKrzysztof Parzyszek 
7454ec4a8e7SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate3) {
7464ec4a8e7SKrzysztof Parzyszek   omp::Object x{"x"};
7474ec4a8e7SKrzysztof Parzyszek 
7484ec4a8e7SKrzysztof Parzyszek   // Allocate + linear
7494ec4a8e7SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
750cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
751*03cbe426SKrzysztof Parzyszek       {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
7524ec4a8e7SKrzysztof Parzyszek   };
7534ec4a8e7SKrzysztof Parzyszek 
7544ec4a8e7SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_for,
7554ec4a8e7SKrzysztof Parzyszek                                   Clauses);
7564ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
7574ec4a8e7SKrzysztof Parzyszek 
7584ec4a8e7SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
7594ec4a8e7SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
7604ec4a8e7SKrzysztof Parzyszek   // The "shared" clause is duplicated---this isn't harmful, but it
7614ec4a8e7SKrzysztof Parzyszek   // should be fixed eventually.
7624ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x) shared(x)"); // (33)
763*03cbe426SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "for linear(, , (x)) firstprivate(x) lastprivate(, (x)) "
764cdbd2287SKrzysztof Parzyszek                   "allocate(, , (x))"); // (33)
7654ec4a8e7SKrzysztof Parzyszek }
7664ec4a8e7SKrzysztof Parzyszek 
7674ec4a8e7SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate4) {
7684ec4a8e7SKrzysztof Parzyszek   omp::Object x{"x"};
7694ec4a8e7SKrzysztof Parzyszek 
7704ec4a8e7SKrzysztof Parzyszek   // Allocate + lastprivate
7714ec4a8e7SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
772cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
7734ec4a8e7SKrzysztof Parzyszek       {OMPC_lastprivate, omp::clause::Lastprivate{{std::nullopt, {x}}}},
7744ec4a8e7SKrzysztof Parzyszek   };
7754ec4a8e7SKrzysztof Parzyszek 
7764ec4a8e7SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
7774ec4a8e7SKrzysztof Parzyszek                                   Clauses);
7784ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
7794ec4a8e7SKrzysztof Parzyszek 
7804ec4a8e7SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
7814ec4a8e7SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
7824ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");                            // (33)
783cdbd2287SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections lastprivate(, (x)) allocate(, , (x))"); // (33)
7844ec4a8e7SKrzysztof Parzyszek }
7854ec4a8e7SKrzysztof Parzyszek 
7864ec4a8e7SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate5) {
7874ec4a8e7SKrzysztof Parzyszek   omp::Object x{"x"};
7884ec4a8e7SKrzysztof Parzyszek 
7894ec4a8e7SKrzysztof Parzyszek   // Allocate + private
790be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
791cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
792be7c9e39SKrzysztof Parzyszek       {OMPC_private, omp::clause::Private{{x}}},
793be7c9e39SKrzysztof Parzyszek   };
794be7c9e39SKrzysztof Parzyszek 
795be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
796be7c9e39SKrzysztof Parzyszek                                   Clauses);
797be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
798be7c9e39SKrzysztof Parzyszek 
799be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
800be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
801be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel");                              // (33)
802cdbd2287SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections private(x) allocate(, , (x))"); // (33)
803be7c9e39SKrzysztof Parzyszek }
804be7c9e39SKrzysztof Parzyszek 
8054ec4a8e7SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Allocate6) {
8064ec4a8e7SKrzysztof Parzyszek   omp::Object x{"x"};
8074ec4a8e7SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
8084ec4a8e7SKrzysztof Parzyszek 
8094ec4a8e7SKrzysztof Parzyszek   // Allocate + reduction
8104ec4a8e7SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
811cdbd2287SKrzysztof Parzyszek       {OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
8124ec4a8e7SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
8134ec4a8e7SKrzysztof Parzyszek   };
8144ec4a8e7SKrzysztof Parzyszek 
8154ec4a8e7SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
8164ec4a8e7SKrzysztof Parzyszek                                   Clauses);
8174ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
8184ec4a8e7SKrzysztof Parzyszek 
8194ec4a8e7SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
8204ec4a8e7SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
8214ec4a8e7SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");                               // (33)
822cdbd2287SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections reduction(, (3), (x)) allocate(, , (x))"); // (33)
8234ec4a8e7SKrzysztof Parzyszek }
8244ec4a8e7SKrzysztof Parzyszek 
825be7c9e39SKrzysztof Parzyszek // REDUCTION
826be7c9e39SKrzysztof Parzyszek // [5.2:134:17-18]
827be7c9e39SKrzysztof Parzyszek // Directives: do, for, loop, parallel, scope, sections, simd, taskloop, teams
828be7c9e39SKrzysztof Parzyszek //
829be7c9e39SKrzysztof Parzyszek // [5.2:340-341:36-13]
830be7c9e39SKrzysztof Parzyszek // (36) The effect of the reduction clause is as if it is applied to all leaf
831be7c9e39SKrzysztof Parzyszek // constructs that permit the clause, except for the following constructs:
832be7c9e39SKrzysztof Parzyszek //  (1) The parallel construct, when combined with the sections,
833be7c9e39SKrzysztof Parzyszek //      worksharing-loop, loop, or taskloop construct; and
834be7c9e39SKrzysztof Parzyszek //  (3) The teams construct, when combined with the loop construct.
835be7c9e39SKrzysztof Parzyszek // (4) For the parallel and teams constructs above, the effect of the reduction
836be7c9e39SKrzysztof Parzyszek // clause instead is as if each list item or, for any list item that is an array
837be7c9e39SKrzysztof Parzyszek // item, its corresponding base array or base pointer appears in a shared clause
838be7c9e39SKrzysztof Parzyszek // for the construct.
839be7c9e39SKrzysztof Parzyszek // (6) If the task reduction-modifier is specified, the effect is as if it only
840be7c9e39SKrzysztof Parzyszek // modifies the behavior of the reduction clause on the innermost leaf construct
841be7c9e39SKrzysztof Parzyszek // that accepts the modifier (see Section 5.5.8).
842be7c9e39SKrzysztof Parzyszek // (8) If the inscan reduction-modifier is specified, the effect is as if it
843be7c9e39SKrzysztof Parzyszek // modifies the behavior of the reduction clause on all constructs of the
844be7c9e39SKrzysztof Parzyszek // combined construct to which the clause is applied and that accept the
845be7c9e39SKrzysztof Parzyszek // modifier.
846be7c9e39SKrzysztof Parzyszek // (10) If a list item in a reduction clause on a combined target construct does
847be7c9e39SKrzysztof Parzyszek // not have the same base variable or base pointer as a list item in a map
848be7c9e39SKrzysztof Parzyszek // clause on the construct, then the effect is as if the list item in the
849be7c9e39SKrzysztof Parzyszek // reduction clause appears as a list item in a map clause with a map-type of
850be7c9e39SKrzysztof Parzyszek // tofrom.
851be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction1) {
852be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
853be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
854be7c9e39SKrzysztof Parzyszek 
855be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
856be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
857be7c9e39SKrzysztof Parzyszek   };
858be7c9e39SKrzysztof Parzyszek 
859be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_sections,
860be7c9e39SKrzysztof Parzyszek                                   Clauses);
861be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
862be7c9e39SKrzysztof Parzyszek 
863be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
864be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
865be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel shared(x)");             // (36), (1), (4)
866be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "sections reduction(, (3), (x))"); // (36)
867be7c9e39SKrzysztof Parzyszek }
868be7c9e39SKrzysztof Parzyszek 
869be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction2) {
870be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
871be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
872be7c9e39SKrzysztof Parzyszek 
873be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
874be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
875be7c9e39SKrzysztof Parzyszek   };
876be7c9e39SKrzysztof Parzyszek 
877be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_masked,
878be7c9e39SKrzysztof Parzyszek                                   Clauses);
879be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
880be7c9e39SKrzysztof Parzyszek 
881be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
882be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
883be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "parallel reduction(, (3), (x))"); // (36), (1), (4)
884be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "masked");                         // (36)
885be7c9e39SKrzysztof Parzyszek }
886be7c9e39SKrzysztof Parzyszek 
887be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction3) {
888be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
889be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
890be7c9e39SKrzysztof Parzyszek 
891be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
892be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
893be7c9e39SKrzysztof Parzyszek   };
894be7c9e39SKrzysztof Parzyszek 
895be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_teams_loop, Clauses);
896be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
897be7c9e39SKrzysztof Parzyszek 
898be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
899be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
900be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams shared(x)");            // (36), (3), (4)
901be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "loop reduction(, (3), (x))"); // (36)
902be7c9e39SKrzysztof Parzyszek }
903be7c9e39SKrzysztof Parzyszek 
904be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction4) {
905be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
906be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
907be7c9e39SKrzysztof Parzyszek 
908be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
909be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
910be7c9e39SKrzysztof Parzyszek   };
911be7c9e39SKrzysztof Parzyszek 
912be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
913be7c9e39SKrzysztof Parzyszek                                   OMPD_teams_distribute_parallel_for, Clauses);
914be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 4u);
915be7c9e39SKrzysztof Parzyszek 
916be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
917be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
918be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
919be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
920be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams reduction(, (3), (x))"); // (36), (3)
921be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "distribute");                  // (36)
922be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "parallel shared(x)");          // (36), (1), (4)
923be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "for reduction(, (3), (x))");   // (36)
924be7c9e39SKrzysztof Parzyszek }
925be7c9e39SKrzysztof Parzyszek 
926be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction5) {
927be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
928be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
929be7c9e39SKrzysztof Parzyszek   auto TaskMod = omp::clause::Reduction::ReductionModifier::Task;
930be7c9e39SKrzysztof Parzyszek 
931be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
932be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{TaskMod, {Add}, {x}}}},
933be7c9e39SKrzysztof Parzyszek   };
934be7c9e39SKrzysztof Parzyszek 
935be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
936be7c9e39SKrzysztof Parzyszek                                   OMPD_teams_distribute_parallel_for, Clauses);
937be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 4u);
938be7c9e39SKrzysztof Parzyszek 
939be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
940be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
941be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
942be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
943be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams reduction(, (3), (x))"); // (36), (3), (6)
944be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "distribute");                  // (36)
945be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "parallel shared(x)");          // (36), (1), (4)
946be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "for reduction(2, (3), (x))");  // (36), (6)
947be7c9e39SKrzysztof Parzyszek }
948be7c9e39SKrzysztof Parzyszek 
949be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction6) {
950be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
951be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
952be7c9e39SKrzysztof Parzyszek   auto InscanMod = omp::clause::Reduction::ReductionModifier::Inscan;
953be7c9e39SKrzysztof Parzyszek 
954be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
955be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{InscanMod, {Add}, {x}}}},
956be7c9e39SKrzysztof Parzyszek   };
957be7c9e39SKrzysztof Parzyszek 
958be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
959be7c9e39SKrzysztof Parzyszek                                   OMPD_teams_distribute_parallel_for, Clauses);
960be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 4u);
961be7c9e39SKrzysztof Parzyszek 
962be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
963be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
964be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
965be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
966be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "teams reduction(, (3), (x))"); // (36), (3), (8)
967be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "distribute");                  // (36)
968be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "parallel shared(x)");          // (36), (1), (4)
969be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "for reduction(1, (3), (x))");  // (36), (8)
970be7c9e39SKrzysztof Parzyszek }
971be7c9e39SKrzysztof Parzyszek 
972be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Reduction7) {
973be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
974be7c9e39SKrzysztof Parzyszek   auto Add = red::makeOp(omp::clause::DefinedOperator::IntrinsicOperator::Add);
975be7c9e39SKrzysztof Parzyszek 
976be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
977be7c9e39SKrzysztof Parzyszek       {OMPC_reduction, omp::clause::Reduction{{std::nullopt, {Add}, {x}}}},
978be7c9e39SKrzysztof Parzyszek   };
979be7c9e39SKrzysztof Parzyszek 
980be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_target_parallel_do,
981be7c9e39SKrzysztof Parzyszek                                   Clauses);
982be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
983be7c9e39SKrzysztof Parzyszek 
984be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
985be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
986be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
987eb88e7c1SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (36), (10)
988be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel shared(x)");       // (36), (1), (4)
989be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "do reduction(, (3), (x))"); // (36)
990be7c9e39SKrzysztof Parzyszek }
991be7c9e39SKrzysztof Parzyszek 
992be7c9e39SKrzysztof Parzyszek // IF
993be7c9e39SKrzysztof Parzyszek // [5.2:72:7-9]
994be7c9e39SKrzysztof Parzyszek // Directives: cancel, parallel, simd, target, target data, target enter data,
995be7c9e39SKrzysztof Parzyszek // target exit data, target update, task, taskloop
996be7c9e39SKrzysztof Parzyszek //
997be7c9e39SKrzysztof Parzyszek // [5.2:72:15-18]
998be7c9e39SKrzysztof Parzyszek // (15) For combined or composite constructs, the if clause only applies to the
999be7c9e39SKrzysztof Parzyszek // semantics of the construct named in the directive-name-modifier.
1000be7c9e39SKrzysztof Parzyszek // (16) For a combined or composite construct, if no directive-name-modifier is
1001be7c9e39SKrzysztof Parzyszek // specified then the if clause applies to all constituent constructs to which
1002be7c9e39SKrzysztof Parzyszek // an if clause can apply.
1003be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, If1) {
1004be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
1005be7c9e39SKrzysztof Parzyszek       {OMPC_if,
1006be7c9e39SKrzysztof Parzyszek        omp::clause::If{{llvm::omp::Directive::OMPD_parallel, omp::ExprTy{}}}},
1007be7c9e39SKrzysztof Parzyszek   };
1008be7c9e39SKrzysztof Parzyszek 
1009be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
1010be7c9e39SKrzysztof Parzyszek                                   OMPD_target_parallel_for_simd, Clauses);
1011be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 4u);
1012be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
1013be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
1014be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
1015be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
1016be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target");              // (15)
1017be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel if(, expr)"); // (15)
1018be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "for");                 // (15)
1019be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "simd");                // (15)
1020be7c9e39SKrzysztof Parzyszek }
1021be7c9e39SKrzysztof Parzyszek 
1022be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, If2) {
1023be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
1024be7c9e39SKrzysztof Parzyszek       {OMPC_if, omp::clause::If{{std::nullopt, omp::ExprTy{}}}},
1025be7c9e39SKrzysztof Parzyszek   };
1026be7c9e39SKrzysztof Parzyszek 
1027be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper,
1028be7c9e39SKrzysztof Parzyszek                                   OMPD_target_parallel_for_simd, Clauses);
1029be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 4u);
1030be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
1031be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
1032be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
1033be7c9e39SKrzysztof Parzyszek   std::string Dir3 = stringify(Dec.output[3]);
1034be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target if(, expr)");   // (16)
1035be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel if(, expr)"); // (16)
1036be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "for");                 // (16)
1037be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir3, "simd if(, expr)");     // (16)
1038be7c9e39SKrzysztof Parzyszek }
1039be7c9e39SKrzysztof Parzyszek 
1040be7c9e39SKrzysztof Parzyszek // LINEAR
1041be7c9e39SKrzysztof Parzyszek // [5.2:118:1-2]
1042be7c9e39SKrzysztof Parzyszek // Directives: declare simd, do, for, simd
1043be7c9e39SKrzysztof Parzyszek //
1044be7c9e39SKrzysztof Parzyszek // [5.2:341:15-22]
1045be7c9e39SKrzysztof Parzyszek // (15.1) The effect of the linear clause is as if it is applied to the
1046be7c9e39SKrzysztof Parzyszek // innermost leaf construct.
1047be7c9e39SKrzysztof Parzyszek // (15.2) Additionally, if the list item is not the iteration variable of a simd
1048be7c9e39SKrzysztof Parzyszek // or worksharing-loop SIMD construct, the effect on the outer leaf constructs
1049be7c9e39SKrzysztof Parzyszek // is as if the list item was specified in firstprivate and lastprivate clauses
1050be7c9e39SKrzysztof Parzyszek // on the combined or composite construct, with the rules specified above
1051be7c9e39SKrzysztof Parzyszek // applied.
1052be7c9e39SKrzysztof Parzyszek // (19) If a list item of the linear clause is the iteration variable of a simd
1053be7c9e39SKrzysztof Parzyszek // or worksharing-loop SIMD construct and it is not declared in the construct,
1054be7c9e39SKrzysztof Parzyszek // the effect on the outer leaf constructs is as if the list item was specified
1055be7c9e39SKrzysztof Parzyszek // in a lastprivate clause on the combined or composite construct with the rules
1056be7c9e39SKrzysztof Parzyszek // specified above applied.
1057be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Linear1) {
1058be7c9e39SKrzysztof Parzyszek   omp::Object x{"x"};
1059be7c9e39SKrzysztof Parzyszek 
1060be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
1061*03cbe426SKrzysztof Parzyszek       {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
1062be7c9e39SKrzysztof Parzyszek   };
1063be7c9e39SKrzysztof Parzyszek 
1064be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_for_simd, Clauses);
1065be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 2u);
1066be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
1067be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
1068be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "for firstprivate(x) lastprivate(, (x))"); // (15.1), (15.2)
1069*03cbe426SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "simd linear(, , (x)) lastprivate(, (x))"); // (15.1)
1070be7c9e39SKrzysztof Parzyszek }
1071be7c9e39SKrzysztof Parzyszek 
1072be7c9e39SKrzysztof Parzyszek // NOWAIT
1073be7c9e39SKrzysztof Parzyszek // [5.2:308:11-13]
1074be7c9e39SKrzysztof Parzyszek // Directives: dispatch, do, for, interop, scope, sections, single, target,
1075be7c9e39SKrzysztof Parzyszek // target enter data, target exit data, target update, taskwait, workshare
1076be7c9e39SKrzysztof Parzyszek //
1077be7c9e39SKrzysztof Parzyszek // [5.2:341:23]
1078be7c9e39SKrzysztof Parzyszek // (23) The effect of the nowait clause is as if it is applied to the outermost
1079be7c9e39SKrzysztof Parzyszek // leaf construct that permits it.
1080be7c9e39SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Nowait1) {
1081be7c9e39SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
1082be7c9e39SKrzysztof Parzyszek       {OMPC_nowait, omp::clause::Nowait{}},
1083be7c9e39SKrzysztof Parzyszek   };
1084be7c9e39SKrzysztof Parzyszek 
1085be7c9e39SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_target_parallel_for,
1086be7c9e39SKrzysztof Parzyszek                                   Clauses);
1087be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 3u);
1088be7c9e39SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
1089be7c9e39SKrzysztof Parzyszek   std::string Dir1 = stringify(Dec.output[1]);
1090be7c9e39SKrzysztof Parzyszek   std::string Dir2 = stringify(Dec.output[2]);
1091be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "target nowait"); // (23)
1092be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir1, "parallel");      // (23)
1093be7c9e39SKrzysztof Parzyszek   ASSERT_EQ(Dir2, "for");           // (23)
1094be7c9e39SKrzysztof Parzyszek }
1095a0c59079SKrzysztof Parzyszek 
1096a0c59079SKrzysztof Parzyszek // ---
1097a0c59079SKrzysztof Parzyszek 
1098a0c59079SKrzysztof Parzyszek // Check that "simd linear(x)" does not fail despite the implied "firstprivate"
1099a0c59079SKrzysztof Parzyszek // (which "simd" does not allow).
1100a0c59079SKrzysztof Parzyszek TEST_F(OpenMPDecompositionTest, Misc1) {
1101a0c59079SKrzysztof Parzyszek   omp::Object x{"x"};
1102a0c59079SKrzysztof Parzyszek   omp::List<omp::Clause> Clauses{
1103*03cbe426SKrzysztof Parzyszek       {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
1104a0c59079SKrzysztof Parzyszek   };
1105a0c59079SKrzysztof Parzyszek 
1106a0c59079SKrzysztof Parzyszek   omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_simd, Clauses);
1107a0c59079SKrzysztof Parzyszek   ASSERT_EQ(Dec.output.size(), 1u);
1108a0c59079SKrzysztof Parzyszek   std::string Dir0 = stringify(Dec.output[0]);
1109*03cbe426SKrzysztof Parzyszek   ASSERT_EQ(Dir0, "simd linear(, , (x)) lastprivate(, (x))");
1110a0c59079SKrzysztof Parzyszek }
1111be7c9e39SKrzysztof Parzyszek } // namespace
1112