xref: /llvm-project/flang/lib/Semantics/check-cuda.cpp (revision 3d59e30cbcfea475594aaf1c69388c0503f846ef)
1f674ddc1SPeter Klausler //===-- lib/Semantics/check-cuda.cpp ----------------------------*- C++ -*-===//
2f674ddc1SPeter Klausler //
3f674ddc1SPeter Klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f674ddc1SPeter Klausler // See https://llvm.org/LICENSE.txt for license information.
5f674ddc1SPeter Klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f674ddc1SPeter Klausler //
7f674ddc1SPeter Klausler //===----------------------------------------------------------------------===//
8f674ddc1SPeter Klausler 
9f674ddc1SPeter Klausler #include "check-cuda.h"
10f674ddc1SPeter Klausler #include "flang/Common/template.h"
11f674ddc1SPeter Klausler #include "flang/Evaluate/fold.h"
120aa982fbSValentin Clement (バレンタイン クレメン) #include "flang/Evaluate/tools.h"
13f674ddc1SPeter Klausler #include "flang/Evaluate/traverse.h"
14f674ddc1SPeter Klausler #include "flang/Parser/parse-tree-visitor.h"
15f674ddc1SPeter Klausler #include "flang/Parser/parse-tree.h"
16f674ddc1SPeter Klausler #include "flang/Parser/tools.h"
17f674ddc1SPeter Klausler #include "flang/Semantics/expression.h"
18f674ddc1SPeter Klausler #include "flang/Semantics/symbol.h"
190aa982fbSValentin Clement (バレンタイン クレメン) #include "flang/Semantics/tools.h"
20f674ddc1SPeter Klausler 
21f674ddc1SPeter Klausler // Once labeled DO constructs have been canonicalized and their parse subtrees
22f674ddc1SPeter Klausler // transformed into parser::DoConstructs, scan the parser::Blocks of the program
23f674ddc1SPeter Klausler // and merge adjacent CUFKernelDoConstructs and DoConstructs whenever the
24f674ddc1SPeter Klausler // CUFKernelDoConstruct doesn't already have an embedded DoConstruct.  Also
25f674ddc1SPeter Klausler // emit errors about improper or missing DoConstructs.
26f674ddc1SPeter Klausler 
27f674ddc1SPeter Klausler namespace Fortran::parser {
28f674ddc1SPeter Klausler struct Mutator {
29f674ddc1SPeter Klausler   template <typename A> bool Pre(A &) { return true; }
30f674ddc1SPeter Klausler   template <typename A> void Post(A &) {}
31f674ddc1SPeter Klausler   bool Pre(Block &);
32f674ddc1SPeter Klausler };
33f674ddc1SPeter Klausler 
34f674ddc1SPeter Klausler bool Mutator::Pre(Block &block) {
35f674ddc1SPeter Klausler   for (auto iter{block.begin()}; iter != block.end(); ++iter) {
36f674ddc1SPeter Klausler     if (auto *kernel{Unwrap<CUFKernelDoConstruct>(*iter)}) {
37f674ddc1SPeter Klausler       auto &nested{std::get<std::optional<DoConstruct>>(kernel->t)};
38f674ddc1SPeter Klausler       if (!nested) {
39f674ddc1SPeter Klausler         if (auto next{iter}; ++next != block.end()) {
40f674ddc1SPeter Klausler           if (auto *doConstruct{Unwrap<DoConstruct>(*next)}) {
41f674ddc1SPeter Klausler             nested = std::move(*doConstruct);
42f674ddc1SPeter Klausler             block.erase(next);
43f674ddc1SPeter Klausler           }
44f674ddc1SPeter Klausler         }
45f674ddc1SPeter Klausler       }
46f674ddc1SPeter Klausler     } else {
47f674ddc1SPeter Klausler       Walk(*iter, *this);
48f674ddc1SPeter Klausler     }
49f674ddc1SPeter Klausler   }
50f674ddc1SPeter Klausler   return false;
51f674ddc1SPeter Klausler }
52f674ddc1SPeter Klausler } // namespace Fortran::parser
53f674ddc1SPeter Klausler 
54f674ddc1SPeter Klausler namespace Fortran::semantics {
55f674ddc1SPeter Klausler 
56f674ddc1SPeter Klausler bool CanonicalizeCUDA(parser::Program &program) {
57f674ddc1SPeter Klausler   parser::Mutator mutator;
58f674ddc1SPeter Klausler   parser::Walk(program, mutator);
59f674ddc1SPeter Klausler   return true;
60f674ddc1SPeter Klausler }
61f674ddc1SPeter Klausler 
62f674ddc1SPeter Klausler using MaybeMsg = std::optional<parser::MessageFormattedText>;
63f674ddc1SPeter Klausler 
64f674ddc1SPeter Klausler // Traverses an evaluate::Expr<> in search of unsupported operations
65f674ddc1SPeter Klausler // on the device.
66f674ddc1SPeter Klausler 
67f674ddc1SPeter Klausler struct DeviceExprChecker
68f674ddc1SPeter Klausler     : public evaluate::AnyTraverse<DeviceExprChecker, MaybeMsg> {
69f674ddc1SPeter Klausler   using Result = MaybeMsg;
70f674ddc1SPeter Klausler   using Base = evaluate::AnyTraverse<DeviceExprChecker, Result>;
71f674ddc1SPeter Klausler   DeviceExprChecker() : Base(*this) {}
72f674ddc1SPeter Klausler   using Base::operator();
73f674ddc1SPeter Klausler   Result operator()(const evaluate::ProcedureDesignator &x) const {
74f674ddc1SPeter Klausler     if (const Symbol * sym{x.GetInterfaceSymbol()}) {
75f674ddc1SPeter Klausler       const auto *subp{
76f674ddc1SPeter Klausler           sym->GetUltimate().detailsIf<semantics::SubprogramDetails>()};
77f674ddc1SPeter Klausler       if (subp) {
78f674ddc1SPeter Klausler         if (auto attrs{subp->cudaSubprogramAttrs()}) {
79f674ddc1SPeter Klausler           if (*attrs == common::CUDASubprogramAttrs::HostDevice ||
80f674ddc1SPeter Klausler               *attrs == common::CUDASubprogramAttrs::Device) {
81f674ddc1SPeter Klausler             return {};
82f674ddc1SPeter Klausler           }
83f674ddc1SPeter Klausler         }
84f674ddc1SPeter Klausler       }
85f674ddc1SPeter Klausler     } else if (x.GetSpecificIntrinsic()) {
86f674ddc1SPeter Klausler       // TODO(CUDA): Check for unsupported intrinsics here
87f674ddc1SPeter Klausler       return {};
88f674ddc1SPeter Klausler     }
89f674ddc1SPeter Klausler     return parser::MessageFormattedText(
90f674ddc1SPeter Klausler         "'%s' may not be called in device code"_err_en_US, x.GetName());
91f674ddc1SPeter Klausler   }
92f674ddc1SPeter Klausler };
93f674ddc1SPeter Klausler 
9473216cd7SPeter Klausler struct FindHostArray
9573216cd7SPeter Klausler     : public evaluate::AnyTraverse<FindHostArray, const Symbol *> {
9673216cd7SPeter Klausler   using Result = const Symbol *;
9773216cd7SPeter Klausler   using Base = evaluate::AnyTraverse<FindHostArray, Result>;
9873216cd7SPeter Klausler   FindHostArray() : Base(*this) {}
9973216cd7SPeter Klausler   using Base::operator();
10073216cd7SPeter Klausler   Result operator()(const evaluate::Component &x) const {
10173216cd7SPeter Klausler     const Symbol &symbol{x.GetLastSymbol()};
10273216cd7SPeter Klausler     if (IsAllocatableOrPointer(symbol)) {
10373216cd7SPeter Klausler       if (Result hostArray{(*this)(symbol)}) {
10473216cd7SPeter Klausler         return hostArray;
10573216cd7SPeter Klausler       }
10673216cd7SPeter Klausler     }
10773216cd7SPeter Klausler     return (*this)(x.base());
10873216cd7SPeter Klausler   }
10973216cd7SPeter Klausler   Result operator()(const Symbol &symbol) const {
11073216cd7SPeter Klausler     if (const auto *details{
11173216cd7SPeter Klausler             symbol.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()}) {
11273216cd7SPeter Klausler       if (details->IsArray() &&
11397b7baceSValentin Clement (バレンタイン クレメン)           !symbol.attrs().test(Fortran::semantics::Attr::PARAMETER) &&
11473216cd7SPeter Klausler           (!details->cudaDataAttr() ||
11573216cd7SPeter Klausler               (details->cudaDataAttr() &&
11673216cd7SPeter Klausler                   *details->cudaDataAttr() != common::CUDADataAttr::Device &&
11781333cfcSValentin Clement (バレンタイン クレメン)                   *details->cudaDataAttr() != common::CUDADataAttr::Constant &&
11873216cd7SPeter Klausler                   *details->cudaDataAttr() != common::CUDADataAttr::Managed &&
11915c61a20SValentin Clement (バレンタイン クレメン)                   *details->cudaDataAttr() != common::CUDADataAttr::Shared &&
12073216cd7SPeter Klausler                   *details->cudaDataAttr() != common::CUDADataAttr::Unified))) {
12173216cd7SPeter Klausler         return &symbol;
12273216cd7SPeter Klausler       }
12373216cd7SPeter Klausler     }
12473216cd7SPeter Klausler     return nullptr;
12573216cd7SPeter Klausler   }
12673216cd7SPeter Klausler };
12773216cd7SPeter Klausler 
128f674ddc1SPeter Klausler template <typename A> static MaybeMsg CheckUnwrappedExpr(const A &x) {
129f674ddc1SPeter Klausler   if (const auto *expr{parser::Unwrap<parser::Expr>(x)}) {
130f674ddc1SPeter Klausler     return DeviceExprChecker{}(expr->typedExpr);
131f674ddc1SPeter Klausler   }
132f674ddc1SPeter Klausler   return {};
133f674ddc1SPeter Klausler }
134f674ddc1SPeter Klausler 
135f674ddc1SPeter Klausler template <typename A>
136f674ddc1SPeter Klausler static void CheckUnwrappedExpr(
137f674ddc1SPeter Klausler     SemanticsContext &context, SourceName at, const A &x) {
138f674ddc1SPeter Klausler   if (const auto *expr{parser::Unwrap<parser::Expr>(x)}) {
139f674ddc1SPeter Klausler     if (auto msg{DeviceExprChecker{}(expr->typedExpr)}) {
140f674ddc1SPeter Klausler       context.Say(at, std::move(*msg));
141f674ddc1SPeter Klausler     }
142f674ddc1SPeter Klausler   }
143f674ddc1SPeter Klausler }
144f674ddc1SPeter Klausler 
145f674ddc1SPeter Klausler template <bool CUF_KERNEL> struct ActionStmtChecker {
146f674ddc1SPeter Klausler   template <typename A> static MaybeMsg WhyNotOk(const A &x) {
147f674ddc1SPeter Klausler     if constexpr (ConstraintTrait<A>) {
148f674ddc1SPeter Klausler       return WhyNotOk(x.thing);
149f674ddc1SPeter Klausler     } else if constexpr (WrapperTrait<A>) {
150f674ddc1SPeter Klausler       return WhyNotOk(x.v);
151f674ddc1SPeter Klausler     } else if constexpr (UnionTrait<A>) {
152f674ddc1SPeter Klausler       return WhyNotOk(x.u);
153f674ddc1SPeter Klausler     } else if constexpr (TupleTrait<A>) {
154f674ddc1SPeter Klausler       return WhyNotOk(x.t);
155f674ddc1SPeter Klausler     } else {
156f674ddc1SPeter Klausler       return parser::MessageFormattedText{
157f674ddc1SPeter Klausler           "Statement may not appear in device code"_err_en_US};
158f674ddc1SPeter Klausler     }
159f674ddc1SPeter Klausler   }
160f674ddc1SPeter Klausler   template <typename A>
161f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const common::Indirection<A> &x) {
162f674ddc1SPeter Klausler     return WhyNotOk(x.value());
163f674ddc1SPeter Klausler   }
164f674ddc1SPeter Klausler   template <typename... As>
165f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const std::variant<As...> &x) {
166f674ddc1SPeter Klausler     return common::visit([](const auto &x) { return WhyNotOk(x); }, x);
167f674ddc1SPeter Klausler   }
168f674ddc1SPeter Klausler   template <std::size_t J = 0, typename... As>
169f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const std::tuple<As...> &x) {
170f674ddc1SPeter Klausler     if constexpr (J == sizeof...(As)) {
171f674ddc1SPeter Klausler       return {};
172f674ddc1SPeter Klausler     } else if (auto msg{WhyNotOk(std::get<J>(x))}) {
173f674ddc1SPeter Klausler       return msg;
174f674ddc1SPeter Klausler     } else {
175f674ddc1SPeter Klausler       return WhyNotOk<(J + 1)>(x);
176f674ddc1SPeter Klausler     }
177f674ddc1SPeter Klausler   }
178f674ddc1SPeter Klausler   template <typename A> static MaybeMsg WhyNotOk(const std::list<A> &x) {
179f674ddc1SPeter Klausler     for (const auto &y : x) {
180f674ddc1SPeter Klausler       if (MaybeMsg result{WhyNotOk(y)}) {
181f674ddc1SPeter Klausler         return result;
182f674ddc1SPeter Klausler       }
183f674ddc1SPeter Klausler     }
184f674ddc1SPeter Klausler     return {};
185f674ddc1SPeter Klausler   }
186f674ddc1SPeter Klausler   template <typename A> static MaybeMsg WhyNotOk(const std::optional<A> &x) {
187f674ddc1SPeter Klausler     if (x) {
188f674ddc1SPeter Klausler       return WhyNotOk(*x);
189f674ddc1SPeter Klausler     } else {
190f674ddc1SPeter Klausler       return {};
191f674ddc1SPeter Klausler     }
192f674ddc1SPeter Klausler   }
193f674ddc1SPeter Klausler   template <typename A>
194f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::UnlabeledStatement<A> &x) {
195f674ddc1SPeter Klausler     return WhyNotOk(x.statement);
196f674ddc1SPeter Klausler   }
197f674ddc1SPeter Klausler   template <typename A>
198f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::Statement<A> &x) {
199f674ddc1SPeter Klausler     return WhyNotOk(x.statement);
200f674ddc1SPeter Klausler   }
201f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::AllocateStmt &) {
202f674ddc1SPeter Klausler     return {}; // AllocateObjects are checked elsewhere
203f674ddc1SPeter Klausler   }
204f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::AllocateCoarraySpec &) {
205f674ddc1SPeter Klausler     return parser::MessageFormattedText(
206f674ddc1SPeter Klausler         "A coarray may not be allocated on the device"_err_en_US);
207f674ddc1SPeter Klausler   }
208f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::DeallocateStmt &) {
209f674ddc1SPeter Klausler     return {}; // AllocateObjects are checked elsewhere
210f674ddc1SPeter Klausler   }
211f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::AssignmentStmt &x) {
212f674ddc1SPeter Klausler     return DeviceExprChecker{}(x.typedAssignment);
213f674ddc1SPeter Klausler   }
214f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::CallStmt &x) {
215f674ddc1SPeter Klausler     return DeviceExprChecker{}(x.typedCall);
216f674ddc1SPeter Klausler   }
217f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::ContinueStmt &) { return {}; }
218f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::IfStmt &x) {
219f674ddc1SPeter Klausler     if (auto result{
220f674ddc1SPeter Klausler             CheckUnwrappedExpr(std::get<parser::ScalarLogicalExpr>(x.t))}) {
221f674ddc1SPeter Klausler       return result;
222f674ddc1SPeter Klausler     }
223f674ddc1SPeter Klausler     return WhyNotOk(
224f674ddc1SPeter Klausler         std::get<parser::UnlabeledStatement<parser::ActionStmt>>(x.t)
225f674ddc1SPeter Klausler             .statement);
226f674ddc1SPeter Klausler   }
227f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::NullifyStmt &x) {
228f674ddc1SPeter Klausler     for (const auto &y : x.v) {
229f674ddc1SPeter Klausler       if (MaybeMsg result{DeviceExprChecker{}(y.typedExpr)}) {
230f674ddc1SPeter Klausler         return result;
231f674ddc1SPeter Klausler       }
232f674ddc1SPeter Klausler     }
233f674ddc1SPeter Klausler     return {};
234f674ddc1SPeter Klausler   }
235f674ddc1SPeter Klausler   static MaybeMsg WhyNotOk(const parser::PointerAssignmentStmt &x) {
236f674ddc1SPeter Klausler     return DeviceExprChecker{}(x.typedAssignment);
237f674ddc1SPeter Klausler   }
238f674ddc1SPeter Klausler };
239f674ddc1SPeter Klausler 
240f674ddc1SPeter Klausler template <bool IsCUFKernelDo> class DeviceContextChecker {
241f674ddc1SPeter Klausler public:
242f674ddc1SPeter Klausler   explicit DeviceContextChecker(SemanticsContext &c) : context_{c} {}
243f674ddc1SPeter Klausler   void CheckSubprogram(const parser::Name &name, const parser::Block &body) {
244f674ddc1SPeter Klausler     if (name.symbol) {
245f674ddc1SPeter Klausler       const auto *subp{
246f674ddc1SPeter Klausler           name.symbol->GetUltimate().detailsIf<SubprogramDetails>()};
247f674ddc1SPeter Klausler       if (subp && subp->moduleInterface()) {
248f674ddc1SPeter Klausler         subp = subp->moduleInterface()
249f674ddc1SPeter Klausler                    ->GetUltimate()
250f674ddc1SPeter Klausler                    .detailsIf<SubprogramDetails>();
251f674ddc1SPeter Klausler       }
252f674ddc1SPeter Klausler       if (subp &&
253f674ddc1SPeter Klausler           subp->cudaSubprogramAttrs().value_or(
254f674ddc1SPeter Klausler               common::CUDASubprogramAttrs::Host) !=
255f674ddc1SPeter Klausler               common::CUDASubprogramAttrs::Host) {
256f674ddc1SPeter Klausler         Check(body);
257f674ddc1SPeter Klausler       }
258f674ddc1SPeter Klausler     }
259f674ddc1SPeter Klausler   }
260f674ddc1SPeter Klausler   void Check(const parser::Block &block) {
261f674ddc1SPeter Klausler     for (const auto &epc : block) {
262f674ddc1SPeter Klausler       Check(epc);
263f674ddc1SPeter Klausler     }
264f674ddc1SPeter Klausler   }
265f674ddc1SPeter Klausler 
266f674ddc1SPeter Klausler private:
267f674ddc1SPeter Klausler   void Check(const parser::ExecutionPartConstruct &epc) {
268f674ddc1SPeter Klausler     common::visit(
269f674ddc1SPeter Klausler         common::visitors{
270f674ddc1SPeter Klausler             [&](const parser::ExecutableConstruct &x) { Check(x); },
271f674ddc1SPeter Klausler             [&](const parser::Statement<common::Indirection<parser::EntryStmt>>
272f674ddc1SPeter Klausler                     &x) {
273f674ddc1SPeter Klausler               context_.Say(x.source,
274f674ddc1SPeter Klausler                   "Device code may not contain an ENTRY statement"_err_en_US);
275f674ddc1SPeter Klausler             },
276f674ddc1SPeter Klausler             [](const parser::Statement<common::Indirection<parser::FormatStmt>>
277f674ddc1SPeter Klausler                     &) {},
278f674ddc1SPeter Klausler             [](const parser::Statement<common::Indirection<parser::DataStmt>>
279f674ddc1SPeter Klausler                     &) {},
280f674ddc1SPeter Klausler             [](const parser::Statement<
281f674ddc1SPeter Klausler                 common::Indirection<parser::NamelistStmt>> &) {},
282f674ddc1SPeter Klausler             [](const parser::ErrorRecovery &) {},
283f674ddc1SPeter Klausler         },
284f674ddc1SPeter Klausler         epc.u);
285f674ddc1SPeter Klausler   }
286f674ddc1SPeter Klausler   void Check(const parser::ExecutableConstruct &ec) {
287f674ddc1SPeter Klausler     common::visit(
288f674ddc1SPeter Klausler         common::visitors{
289f674ddc1SPeter Klausler             [&](const parser::Statement<parser::ActionStmt> &stmt) {
290f674ddc1SPeter Klausler               Check(stmt.statement, stmt.source);
291f674ddc1SPeter Klausler             },
292f674ddc1SPeter Klausler             [&](const common::Indirection<parser::DoConstruct> &x) {
293f674ddc1SPeter Klausler               if (const std::optional<parser::LoopControl> &control{
294f674ddc1SPeter Klausler                       x.value().GetLoopControl()}) {
295f674ddc1SPeter Klausler                 common::visit([&](const auto &y) { Check(y); }, control->u);
296f674ddc1SPeter Klausler               }
297f674ddc1SPeter Klausler               Check(std::get<parser::Block>(x.value().t));
298f674ddc1SPeter Klausler             },
299f674ddc1SPeter Klausler             [&](const common::Indirection<parser::BlockConstruct> &x) {
300f674ddc1SPeter Klausler               Check(std::get<parser::Block>(x.value().t));
301f674ddc1SPeter Klausler             },
302f674ddc1SPeter Klausler             [&](const common::Indirection<parser::IfConstruct> &x) {
303f674ddc1SPeter Klausler               Check(x.value());
304f674ddc1SPeter Klausler             },
305e3dafa88SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::CaseConstruct> &x) {
306e3dafa88SValentin Clement (バレンタイン クレメン)               const auto &caseList{
307e3dafa88SValentin Clement (バレンタイン クレメン)                   std::get<std::list<parser::CaseConstruct::Case>>(
308e3dafa88SValentin Clement (バレンタイン クレメン)                       x.value().t)};
309e3dafa88SValentin Clement (バレンタイン クレメン)               for (const parser::CaseConstruct::Case &c : caseList) {
310e3dafa88SValentin Clement (バレンタイン クレメン)                 Check(std::get<parser::Block>(c.t));
311e3dafa88SValentin Clement (バレンタイン クレメン)               }
312e3dafa88SValentin Clement (バレンタイン クレメン)             },
313f674ddc1SPeter Klausler             [&](const auto &x) {
314f674ddc1SPeter Klausler               if (auto source{parser::GetSource(x)}) {
315f674ddc1SPeter Klausler                 context_.Say(*source,
316f674ddc1SPeter Klausler                     "Statement may not appear in device code"_err_en_US);
317f674ddc1SPeter Klausler               }
318f674ddc1SPeter Klausler             },
319f674ddc1SPeter Klausler         },
320f674ddc1SPeter Klausler         ec.u);
321f674ddc1SPeter Klausler   }
322896b5e55SValentin Clement (バレンタイン クレメン)   template <typename SEEK, typename A>
323896b5e55SValentin Clement (バレンタイン クレメン)   static const SEEK *GetIOControl(const A &stmt) {
324896b5e55SValentin Clement (バレンタイン クレメン)     for (const auto &spec : stmt.controls) {
325896b5e55SValentin Clement (バレンタイン クレメン)       if (const auto *result{std::get_if<SEEK>(&spec.u)}) {
326896b5e55SValentin Clement (バレンタイン クレメン)         return result;
327896b5e55SValentin Clement (バレンタイン クレメン)       }
328896b5e55SValentin Clement (バレンタイン クレメン)     }
329896b5e55SValentin Clement (バレンタイン クレメン)     return nullptr;
330896b5e55SValentin Clement (バレンタイン クレメン)   }
331896b5e55SValentin Clement (バレンタイン クレメン)   template <typename A> static bool IsInternalIO(const A &stmt) {
332896b5e55SValentin Clement (バレンタイン クレメン)     if (stmt.iounit.has_value()) {
333896b5e55SValentin Clement (バレンタイン クレメン)       return std::holds_alternative<Fortran::parser::Variable>(stmt.iounit->u);
334896b5e55SValentin Clement (バレンタイン クレメン)     }
335896b5e55SValentin Clement (バレンタイン クレメン)     if (auto *unit{GetIOControl<Fortran::parser::IoUnit>(stmt)}) {
336896b5e55SValentin Clement (バレンタイン クレメン)       return std::holds_alternative<Fortran::parser::Variable>(unit->u);
337896b5e55SValentin Clement (バレンタイン クレメン)     }
338896b5e55SValentin Clement (バレンタイン クレメン)     return false;
339896b5e55SValentin Clement (バレンタイン クレメン)   }
340896b5e55SValentin Clement (バレンタイン クレメン)   void WarnOnIoStmt(const parser::CharBlock &source) {
3410f973ac7SPeter Klausler     context_.Warn(common::UsageWarning::CUDAUsage, source,
3420f973ac7SPeter Klausler         "I/O statement might not be supported on device"_warn_en_US);
343505f6da1SPeter Klausler   }
344896b5e55SValentin Clement (バレンタイン クレメン)   template <typename A>
345896b5e55SValentin Clement (バレンタイン クレメン)   void WarnIfNotInternal(const A &stmt, const parser::CharBlock &source) {
346896b5e55SValentin Clement (バレンタイン クレメン)     if (!IsInternalIO(stmt)) {
347896b5e55SValentin Clement (バレンタイン クレメン)       WarnOnIoStmt(source);
348896b5e55SValentin Clement (バレンタイン クレメン)     }
349896b5e55SValentin Clement (バレンタイン クレメン)   }
35016975ad2SValentin Clement (バレンタイン クレメン)   template <typename A>
35173216cd7SPeter Klausler   void ErrorIfHostSymbol(const A &expr, parser::CharBlock source) {
35273216cd7SPeter Klausler     if (const Symbol * hostArray{FindHostArray{}(expr)}) {
35316975ad2SValentin Clement (バレンタイン クレメン)       context_.Say(source,
35467ae944bSValentin Clement (バレンタイン クレメン)           "Host array '%s' cannot be present in device context"_err_en_US,
35573216cd7SPeter Klausler           hostArray->name());
35616975ad2SValentin Clement (バレンタイン クレメン)     }
35716975ad2SValentin Clement (バレンタイン クレメン)   }
358e3dafa88SValentin Clement (バレンタイン クレメン)   void ErrorInCUFKernel(parser::CharBlock source) {
359e3dafa88SValentin Clement (バレンタイン クレメン)     if (IsCUFKernelDo) {
360e3dafa88SValentin Clement (バレンタイン クレメン)       context_.Say(
361e3dafa88SValentin Clement (バレンタイン クレメン)           source, "Statement may not appear in cuf kernel code"_err_en_US);
362e3dafa88SValentin Clement (バレンタイン クレメン)     }
363e3dafa88SValentin Clement (バレンタイン クレメン)   }
364f674ddc1SPeter Klausler   void Check(const parser::ActionStmt &stmt, const parser::CharBlock &source) {
365f674ddc1SPeter Klausler     common::visit(
366f674ddc1SPeter Klausler         common::visitors{
367e3dafa88SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::CycleStmt> &) {
368e3dafa88SValentin Clement (バレンタイン クレメン)               ErrorInCUFKernel(source);
369e3dafa88SValentin Clement (バレンタイン クレメン)             },
370e3dafa88SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::ExitStmt> &) {
371e3dafa88SValentin Clement (バレンタイン クレメン)               ErrorInCUFKernel(source);
372e3dafa88SValentin Clement (バレンタイン クレメン)             },
373e3dafa88SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::GotoStmt> &) {
374e3dafa88SValentin Clement (バレンタイン クレメン)               ErrorInCUFKernel(source);
375e3dafa88SValentin Clement (バレンタイン クレメン)             },
3767009b069SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::StopStmt> &) { return; },
377896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::PrintStmt> &) {},
378896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::WriteStmt> &x) {
379896b5e55SValentin Clement (バレンタイン クレメン)               if (x.value().format) { // Formatted write to '*' or '6'
380896b5e55SValentin Clement (バレンタイン クレメン)                 if (std::holds_alternative<Fortran::parser::Star>(
381896b5e55SValentin Clement (バレンタイン クレメン)                         x.value().format->u)) {
382896b5e55SValentin Clement (バレンタイン クレメン)                   if (x.value().iounit) {
383896b5e55SValentin Clement (バレンタイン クレメン)                     if (std::holds_alternative<Fortran::parser::Star>(
384896b5e55SValentin Clement (バレンタイン クレメン)                             x.value().iounit->u)) {
385896b5e55SValentin Clement (バレンタイン クレメン)                       return;
386896b5e55SValentin Clement (バレンタイン クレメン)                     }
387896b5e55SValentin Clement (バレンタイン クレメン)                   }
388896b5e55SValentin Clement (バレンタイン クレメン)                 }
389896b5e55SValentin Clement (バレンタイン クレメン)               }
390896b5e55SValentin Clement (バレンタイン クレメン)               WarnIfNotInternal(x.value(), source);
391896b5e55SValentin Clement (バレンタイン クレメン)             },
392896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::CloseStmt> &x) {
393896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
394896b5e55SValentin Clement (バレンタイン クレメン)             },
395896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::EndfileStmt> &x) {
396896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
397896b5e55SValentin Clement (バレンタイン クレメン)             },
398896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::OpenStmt> &x) {
399896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
400896b5e55SValentin Clement (バレンタイン クレメン)             },
401896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::ReadStmt> &x) {
402896b5e55SValentin Clement (バレンタイン クレメン)               WarnIfNotInternal(x.value(), source);
403896b5e55SValentin Clement (バレンタイン クレメン)             },
404896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::InquireStmt> &x) {
405896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
406896b5e55SValentin Clement (バレンタイン クレメン)             },
407896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::RewindStmt> &x) {
408896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
409896b5e55SValentin Clement (バレンタイン クレメン)             },
410896b5e55SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::BackspaceStmt> &x) {
411896b5e55SValentin Clement (バレンタイン クレメン)               WarnOnIoStmt(source);
412896b5e55SValentin Clement (バレンタイン クレメン)             },
413a309c07aSValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::IfStmt> &x) {
414a309c07aSValentin Clement (バレンタイン クレメン)               Check(x.value());
415a309c07aSValentin Clement (バレンタイン クレメン)             },
41616975ad2SValentin Clement (バレンタイン クレメン)             [&](const common::Indirection<parser::AssignmentStmt> &x) {
41767ae944bSValentin Clement (バレンタイン クレメン)               if (const evaluate::Assignment *
41867ae944bSValentin Clement (バレンタイン クレメン)                   assign{semantics::GetAssignment(x.value())}) {
41916975ad2SValentin Clement (バレンタイン クレメン)                 ErrorIfHostSymbol(assign->lhs, source);
42016975ad2SValentin Clement (バレンタイン クレメン)                 ErrorIfHostSymbol(assign->rhs, source);
42116975ad2SValentin Clement (バレンタイン クレメン)               }
42216975ad2SValentin Clement (バレンタイン クレメン)               if (auto msg{ActionStmtChecker<IsCUFKernelDo>::WhyNotOk(x)}) {
42316975ad2SValentin Clement (バレンタイン クレメン)                 context_.Say(source, std::move(*msg));
42416975ad2SValentin Clement (バレンタイン クレメン)               }
42516975ad2SValentin Clement (バレンタイン クレメン)             },
426f674ddc1SPeter Klausler             [&](const auto &x) {
427f674ddc1SPeter Klausler               if (auto msg{ActionStmtChecker<IsCUFKernelDo>::WhyNotOk(x)}) {
428f674ddc1SPeter Klausler                 context_.Say(source, std::move(*msg));
429f674ddc1SPeter Klausler               }
430f674ddc1SPeter Klausler             },
431f674ddc1SPeter Klausler         },
432f674ddc1SPeter Klausler         stmt.u);
433f674ddc1SPeter Klausler   }
434f674ddc1SPeter Klausler   void Check(const parser::IfConstruct &ic) {
435f674ddc1SPeter Klausler     const auto &ifS{std::get<parser::Statement<parser::IfThenStmt>>(ic.t)};
436f674ddc1SPeter Klausler     CheckUnwrappedExpr(context_, ifS.source,
437f674ddc1SPeter Klausler         std::get<parser::ScalarLogicalExpr>(ifS.statement.t));
438f674ddc1SPeter Klausler     Check(std::get<parser::Block>(ic.t));
439f674ddc1SPeter Klausler     for (const auto &eib :
440f674ddc1SPeter Klausler         std::get<std::list<parser::IfConstruct::ElseIfBlock>>(ic.t)) {
441f674ddc1SPeter Klausler       const auto &eIfS{std::get<parser::Statement<parser::ElseIfStmt>>(eib.t)};
442f674ddc1SPeter Klausler       CheckUnwrappedExpr(context_, eIfS.source,
443f674ddc1SPeter Klausler           std::get<parser::ScalarLogicalExpr>(eIfS.statement.t));
444f674ddc1SPeter Klausler       Check(std::get<parser::Block>(eib.t));
445f674ddc1SPeter Klausler     }
446f674ddc1SPeter Klausler     if (const auto &eb{
447f674ddc1SPeter Klausler             std::get<std::optional<parser::IfConstruct::ElseBlock>>(ic.t)}) {
448f674ddc1SPeter Klausler       Check(std::get<parser::Block>(eb->t));
449f674ddc1SPeter Klausler     }
450f674ddc1SPeter Klausler   }
451a309c07aSValentin Clement (バレンタイン クレメン)   void Check(const parser::IfStmt &is) {
452a309c07aSValentin Clement (バレンタイン クレメン)     const auto &uS{
453a309c07aSValentin Clement (バレンタイン クレメン)         std::get<parser::UnlabeledStatement<parser::ActionStmt>>(is.t)};
454a309c07aSValentin Clement (バレンタイン クレメン)     CheckUnwrappedExpr(
455a309c07aSValentin Clement (バレンタイン クレメン)         context_, uS.source, std::get<parser::ScalarLogicalExpr>(is.t));
456a309c07aSValentin Clement (バレンタイン クレメン)     Check(uS.statement, uS.source);
457a309c07aSValentin Clement (バレンタイン クレメン)   }
458f674ddc1SPeter Klausler   void Check(const parser::LoopControl::Bounds &bounds) {
459f674ddc1SPeter Klausler     Check(bounds.lower);
460f674ddc1SPeter Klausler     Check(bounds.upper);
461f674ddc1SPeter Klausler     if (bounds.step) {
462f674ddc1SPeter Klausler       Check(*bounds.step);
463f674ddc1SPeter Klausler     }
464f674ddc1SPeter Klausler   }
465f674ddc1SPeter Klausler   void Check(const parser::LoopControl::Concurrent &x) {
466f674ddc1SPeter Klausler     const auto &header{std::get<parser::ConcurrentHeader>(x.t)};
467f674ddc1SPeter Klausler     for (const auto &cc :
468f674ddc1SPeter Klausler         std::get<std::list<parser::ConcurrentControl>>(header.t)) {
469f674ddc1SPeter Klausler       Check(std::get<1>(cc.t));
470f674ddc1SPeter Klausler       Check(std::get<2>(cc.t));
471f674ddc1SPeter Klausler       if (const auto &step{
472f674ddc1SPeter Klausler               std::get<std::optional<parser::ScalarIntExpr>>(cc.t)}) {
473f674ddc1SPeter Klausler         Check(*step);
474f674ddc1SPeter Klausler       }
475f674ddc1SPeter Klausler     }
476f674ddc1SPeter Klausler     if (const auto &mask{
477f674ddc1SPeter Klausler             std::get<std::optional<parser::ScalarLogicalExpr>>(header.t)}) {
478f674ddc1SPeter Klausler       Check(*mask);
479f674ddc1SPeter Klausler     }
480f674ddc1SPeter Klausler   }
481f674ddc1SPeter Klausler   void Check(const parser::ScalarLogicalExpr &x) {
482f674ddc1SPeter Klausler     Check(DEREF(parser::Unwrap<parser::Expr>(x)));
483f674ddc1SPeter Klausler   }
484f674ddc1SPeter Klausler   void Check(const parser::ScalarIntExpr &x) {
485f674ddc1SPeter Klausler     Check(DEREF(parser::Unwrap<parser::Expr>(x)));
486f674ddc1SPeter Klausler   }
487f674ddc1SPeter Klausler   void Check(const parser::ScalarExpr &x) {
488f674ddc1SPeter Klausler     Check(DEREF(parser::Unwrap<parser::Expr>(x)));
489f674ddc1SPeter Klausler   }
490f674ddc1SPeter Klausler   void Check(const parser::Expr &expr) {
491f674ddc1SPeter Klausler     if (MaybeMsg msg{DeviceExprChecker{}(expr.typedExpr)}) {
492f674ddc1SPeter Klausler       context_.Say(expr.source, std::move(*msg));
493f674ddc1SPeter Klausler     }
494f674ddc1SPeter Klausler   }
495f674ddc1SPeter Klausler 
496f674ddc1SPeter Klausler   SemanticsContext &context_;
497f674ddc1SPeter Klausler };
498f674ddc1SPeter Klausler 
499f674ddc1SPeter Klausler void CUDAChecker::Enter(const parser::SubroutineSubprogram &x) {
500f674ddc1SPeter Klausler   DeviceContextChecker<false>{context_}.CheckSubprogram(
501f674ddc1SPeter Klausler       std::get<parser::Name>(
502f674ddc1SPeter Klausler           std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t),
503f674ddc1SPeter Klausler       std::get<parser::ExecutionPart>(x.t).v);
504f674ddc1SPeter Klausler }
505f674ddc1SPeter Klausler 
506f674ddc1SPeter Klausler void CUDAChecker::Enter(const parser::FunctionSubprogram &x) {
507f674ddc1SPeter Klausler   DeviceContextChecker<false>{context_}.CheckSubprogram(
508f674ddc1SPeter Klausler       std::get<parser::Name>(
509f674ddc1SPeter Klausler           std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t),
510f674ddc1SPeter Klausler       std::get<parser::ExecutionPart>(x.t).v);
511f674ddc1SPeter Klausler }
512f674ddc1SPeter Klausler 
513f674ddc1SPeter Klausler void CUDAChecker::Enter(const parser::SeparateModuleSubprogram &x) {
514f674ddc1SPeter Klausler   DeviceContextChecker<false>{context_}.CheckSubprogram(
515f674ddc1SPeter Klausler       std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t).statement.v,
516f674ddc1SPeter Klausler       std::get<parser::ExecutionPart>(x.t).v);
517f674ddc1SPeter Klausler }
518f674ddc1SPeter Klausler 
519f674ddc1SPeter Klausler // !$CUF KERNEL DO semantic checks
520f674ddc1SPeter Klausler 
521f674ddc1SPeter Klausler static int DoConstructTightNesting(
522f674ddc1SPeter Klausler     const parser::DoConstruct *doConstruct, const parser::Block *&innerBlock) {
523*3d59e30cSValentin Clement (バレンタイン クレメン)   if (!doConstruct ||
524*3d59e30cSValentin Clement (バレンタイン クレメン)       (!doConstruct->IsDoNormal() && !doConstruct->IsDoConcurrent())) {
525f674ddc1SPeter Klausler     return 0;
526f674ddc1SPeter Klausler   }
527f674ddc1SPeter Klausler   innerBlock = &std::get<parser::Block>(doConstruct->t);
528f674ddc1SPeter Klausler   if (innerBlock->size() == 1) {
529f674ddc1SPeter Klausler     if (const auto *execConstruct{
530f674ddc1SPeter Klausler             std::get_if<parser::ExecutableConstruct>(&innerBlock->front().u)}) {
531f674ddc1SPeter Klausler       if (const auto *next{
532f674ddc1SPeter Klausler               std::get_if<common::Indirection<parser::DoConstruct>>(
533f674ddc1SPeter Klausler                   &execConstruct->u)}) {
534f674ddc1SPeter Klausler         return 1 + DoConstructTightNesting(&next->value(), innerBlock);
535f674ddc1SPeter Klausler       }
536f674ddc1SPeter Klausler     }
537f674ddc1SPeter Klausler   }
538f674ddc1SPeter Klausler   return 1;
539f674ddc1SPeter Klausler }
540f674ddc1SPeter Klausler 
5415bbb63bdSPeter Klausler static void CheckReduce(
5425bbb63bdSPeter Klausler     SemanticsContext &context, const parser::CUFReduction &reduce) {
5435bbb63bdSPeter Klausler   auto op{std::get<parser::CUFReduction::Operator>(reduce.t).v};
5445bbb63bdSPeter Klausler   for (const auto &var :
5455bbb63bdSPeter Klausler       std::get<std::list<parser::Scalar<parser::Variable>>>(reduce.t)) {
5465bbb63bdSPeter Klausler     if (const auto &typedExprPtr{var.thing.typedExpr};
5475bbb63bdSPeter Klausler         typedExprPtr && typedExprPtr->v) {
5485bbb63bdSPeter Klausler       const auto &expr{*typedExprPtr->v};
5495bbb63bdSPeter Klausler       if (auto type{expr.GetType()}) {
5505bbb63bdSPeter Klausler         auto cat{type->category()};
5515bbb63bdSPeter Klausler         bool isOk{false};
5525bbb63bdSPeter Klausler         switch (op) {
5533af717d6Skhaki3         case parser::ReductionOperator::Operator::Plus:
5543af717d6Skhaki3         case parser::ReductionOperator::Operator::Multiply:
5553af717d6Skhaki3         case parser::ReductionOperator::Operator::Max:
5563af717d6Skhaki3         case parser::ReductionOperator::Operator::Min:
5574065d985SValentin Clement (バレンタイン クレメン)           isOk = cat == TypeCategory::Integer || cat == TypeCategory::Real ||
5584065d985SValentin Clement (バレンタイン クレメン)               cat == TypeCategory::Complex;
5595bbb63bdSPeter Klausler           break;
5603af717d6Skhaki3         case parser::ReductionOperator::Operator::Iand:
5613af717d6Skhaki3         case parser::ReductionOperator::Operator::Ior:
5623af717d6Skhaki3         case parser::ReductionOperator::Operator::Ieor:
5635bbb63bdSPeter Klausler           isOk = cat == TypeCategory::Integer;
5645bbb63bdSPeter Klausler           break;
5653af717d6Skhaki3         case parser::ReductionOperator::Operator::And:
5663af717d6Skhaki3         case parser::ReductionOperator::Operator::Or:
5673af717d6Skhaki3         case parser::ReductionOperator::Operator::Eqv:
5683af717d6Skhaki3         case parser::ReductionOperator::Operator::Neqv:
5695bbb63bdSPeter Klausler           isOk = cat == TypeCategory::Logical;
5705bbb63bdSPeter Klausler           break;
5715bbb63bdSPeter Klausler         }
5725bbb63bdSPeter Klausler         if (!isOk) {
5735bbb63bdSPeter Klausler           context.Say(var.thing.GetSource(),
5745bbb63bdSPeter Klausler               "!$CUF KERNEL DO REDUCE operation is not acceptable for a variable with type %s"_err_en_US,
5755bbb63bdSPeter Klausler               type->AsFortran());
5765bbb63bdSPeter Klausler         }
5775bbb63bdSPeter Klausler       }
5785bbb63bdSPeter Klausler     }
5795bbb63bdSPeter Klausler   }
5805bbb63bdSPeter Klausler }
5815bbb63bdSPeter Klausler 
582f674ddc1SPeter Klausler void CUDAChecker::Enter(const parser::CUFKernelDoConstruct &x) {
583f674ddc1SPeter Klausler   auto source{std::get<parser::CUFKernelDoConstruct::Directive>(x.t).source};
584f674ddc1SPeter Klausler   const auto &directive{std::get<parser::CUFKernelDoConstruct::Directive>(x.t)};
585f674ddc1SPeter Klausler   std::int64_t depth{1};
586f674ddc1SPeter Klausler   if (auto expr{AnalyzeExpr(context_,
587f674ddc1SPeter Klausler           std::get<std::optional<parser::ScalarIntConstantExpr>>(
588f674ddc1SPeter Klausler               directive.t))}) {
589f674ddc1SPeter Klausler     depth = evaluate::ToInt64(expr).value_or(0);
590f674ddc1SPeter Klausler     if (depth <= 0) {
591f674ddc1SPeter Klausler       context_.Say(source,
592f674ddc1SPeter Klausler           "!$CUF KERNEL DO (%jd): loop nesting depth must be positive"_err_en_US,
593f674ddc1SPeter Klausler           std::intmax_t{depth});
594f674ddc1SPeter Klausler       depth = 1;
595f674ddc1SPeter Klausler     }
596f674ddc1SPeter Klausler   }
597f674ddc1SPeter Klausler   const parser::DoConstruct *doConstruct{common::GetPtrFromOptional(
598f674ddc1SPeter Klausler       std::get<std::optional<parser::DoConstruct>>(x.t))};
599f674ddc1SPeter Klausler   const parser::Block *innerBlock{nullptr};
600f674ddc1SPeter Klausler   if (DoConstructTightNesting(doConstruct, innerBlock) < depth) {
601f674ddc1SPeter Klausler     context_.Say(source,
602f674ddc1SPeter Klausler         "!$CUF KERNEL DO (%jd) must be followed by a DO construct with tightly nested outer levels of counted DO loops"_err_en_US,
603f674ddc1SPeter Klausler         std::intmax_t{depth});
604f674ddc1SPeter Klausler   }
605f674ddc1SPeter Klausler   if (innerBlock) {
606f674ddc1SPeter Klausler     DeviceContextChecker<true>{context_}.Check(*innerBlock);
607f674ddc1SPeter Klausler   }
6085bbb63bdSPeter Klausler   for (const auto &reduce :
6095bbb63bdSPeter Klausler       std::get<std::list<parser::CUFReduction>>(directive.t)) {
6105bbb63bdSPeter Klausler     CheckReduce(context_, reduce);
6115bbb63bdSPeter Klausler   }
612cfc09511SValentin Clement (バレンタイン クレメン)   inCUFKernelDoConstruct_ = true;
613cfc09511SValentin Clement (バレンタイン クレメン) }
614cfc09511SValentin Clement (バレンタイン クレメン) 
615cfc09511SValentin Clement (バレンタイン クレメン) void CUDAChecker::Leave(const parser::CUFKernelDoConstruct &) {
616cfc09511SValentin Clement (バレンタイン クレメン)   inCUFKernelDoConstruct_ = false;
617f674ddc1SPeter Klausler }
618f674ddc1SPeter Klausler 
6190aa982fbSValentin Clement (バレンタイン クレメン) void CUDAChecker::Enter(const parser::AssignmentStmt &x) {
6207b6b0231SValentin Clement (バレンタイン クレメン)   auto lhsLoc{std::get<parser::Variable>(x.t).GetSource()};
6217b6b0231SValentin Clement (バレンタイン クレメン)   const auto &scope{context_.FindScope(lhsLoc)};
6227b6b0231SValentin Clement (バレンタイン クレメン)   const Scope &progUnit{GetProgramUnitContaining(scope)};
623cfc09511SValentin Clement (バレンタイン クレメン)   if (IsCUDADeviceContext(&progUnit) || inCUFKernelDoConstruct_) {
6247b6b0231SValentin Clement (バレンタイン クレメン)     return; // Data transfer with assignment is only perform on host.
6257b6b0231SValentin Clement (バレンタイン クレメン)   }
6267b6b0231SValentin Clement (バレンタイン クレメン) 
6270aa982fbSValentin Clement (バレンタイン クレメン)   const evaluate::Assignment *assign{semantics::GetAssignment(x)};
62826101e8cSValentin Clement (バレンタイン クレメン)   if (!assign) {
62926101e8cSValentin Clement (バレンタイン クレメン)     return;
63026101e8cSValentin Clement (バレンタイン クレメン)   }
63126101e8cSValentin Clement (バレンタイン クレメン) 
6328e8dccdeSValentin Clement (バレンタイン クレメン)   int nbLhs{evaluate::GetNbOfCUDADeviceSymbols(assign->lhs)};
6338e8dccdeSValentin Clement (バレンタイン クレメン)   int nbRhs{evaluate::GetNbOfCUDADeviceSymbols(assign->rhs)};
6340aa982fbSValentin Clement (バレンタイン クレメン) 
6350aa982fbSValentin Clement (バレンタイン クレメン)   // device to host transfer with more than one device object on the rhs is not
6360aa982fbSValentin Clement (バレンタイン クレメン)   // legal.
6370aa982fbSValentin Clement (バレンタイン クレメン)   if (nbLhs == 0 && nbRhs > 1) {
6380aa982fbSValentin Clement (バレンタイン クレメン)     context_.Say(lhsLoc,
6390aa982fbSValentin Clement (バレンタイン クレメン)         "More than one reference to a CUDA object on the right hand side of the assigment"_err_en_US);
6400aa982fbSValentin Clement (バレンタイン クレメン)   }
6410aa982fbSValentin Clement (バレンタイン クレメン) }
6420aa982fbSValentin Clement (バレンタイン クレメン) 
643f674ddc1SPeter Klausler } // namespace Fortran::semantics
644