1 //===-- OpenACC.cpp -- OpenACC directive lowering -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Lower/OpenACC.h"
14 #include "flang/Common/idioms.h"
15 #include "flang/Lower/Bridge.h"
16 #include "flang/Lower/PFTBuilder.h"
17 #include "flang/Lower/StatementContext.h"
18 #include "flang/Lower/Todo.h"
19 #include "flang/Optimizer/Builder/BoxValue.h"
20 #include "flang/Optimizer/Builder/FIRBuilder.h"
21 #include "flang/Parser/parse-tree.h"
22 #include "flang/Semantics/tools.h"
23 #include "mlir/Dialect/OpenACC/OpenACC.h"
24 #include "llvm/Frontend/OpenACC/ACC.h.inc"
25 
26 using namespace mlir;
27 
28 static const Fortran::parser::Name *
29 getDesignatorNameIfDataRef(const Fortran::parser::Designator &designator) {
30   const auto *dataRef{std::get_if<Fortran::parser::DataRef>(&designator.u)};
31   return dataRef ? std::get_if<Fortran::parser::Name>(&dataRef->u) : nullptr;
32 }
33 
34 static void genObjectList(const Fortran::parser::AccObjectList &objectList,
35                           Fortran::lower::AbstractConverter &converter,
36                           SmallVectorImpl<Value> &operands) {
37   for (const auto &accObject : objectList.v) {
38     std::visit(
39         Fortran::common::visitors{
40             [&](const Fortran::parser::Designator &designator) {
41               if (const auto *name = getDesignatorNameIfDataRef(designator)) {
42                 const auto variable = converter.getSymbolAddress(*name->symbol);
43                 operands.push_back(variable);
44               }
45             },
46             [&](const Fortran::parser::Name &name) {
47               const auto variable = converter.getSymbolAddress(*name.symbol);
48               operands.push_back(variable);
49             }},
50         accObject.u);
51   }
52 }
53 
54 template <typename Clause>
55 static void
56 genObjectListWithModifier(const Clause *x,
57                           Fortran::lower::AbstractConverter &converter,
58                           Fortran::parser::AccDataModifier::Modifier mod,
59                           SmallVectorImpl<Value> &operandsWithModifier,
60                           SmallVectorImpl<Value> &operands) {
61   const Fortran::parser::AccObjectListWithModifier &listWithModifier = x->v;
62   const Fortran::parser::AccObjectList &accObjectList =
63       std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
64   const auto &modifier =
65       std::get<std::optional<Fortran::parser::AccDataModifier>>(
66           listWithModifier.t);
67   if (modifier && (*modifier).v == mod) {
68     genObjectList(accObjectList, converter, operandsWithModifier);
69   } else {
70     genObjectList(accObjectList, converter, operands);
71   }
72 }
73 
74 static void addOperands(SmallVectorImpl<Value> &operands,
75                         SmallVectorImpl<int32_t> &operandSegments,
76                         const SmallVectorImpl<Value> &clauseOperands) {
77   operands.append(clauseOperands.begin(), clauseOperands.end());
78   operandSegments.push_back(clauseOperands.size());
79 }
80 
81 static void addOperand(SmallVectorImpl<Value> &operands,
82                        SmallVectorImpl<int32_t> &operandSegments,
83                        const Value &clauseOperand) {
84   if (clauseOperand) {
85     operands.push_back(clauseOperand);
86     operandSegments.push_back(1);
87   } else {
88     operandSegments.push_back(0);
89   }
90 }
91 
92 template <typename Op, typename Terminator>
93 static Op createRegionOp(fir::FirOpBuilder &builder, mlir::Location loc,
94                          const SmallVectorImpl<Value> &operands,
95                          const SmallVectorImpl<int32_t> &operandSegments) {
96   llvm::ArrayRef<mlir::Type> argTy;
97   Op op = builder.create<Op>(loc, argTy, operands);
98   builder.createBlock(&op.getRegion());
99   auto &block = op.getRegion().back();
100   builder.setInsertionPointToStart(&block);
101   builder.create<Terminator>(loc);
102 
103   op->setAttr(Op::getOperandSegmentSizeAttr(),
104               builder.getI32VectorAttr(operandSegments));
105 
106   // Place the insertion point to the start of the first block.
107   builder.setInsertionPointToStart(&block);
108 
109   return op;
110 }
111 
112 template <typename Op>
113 static Op createSimpleOp(fir::FirOpBuilder &builder, mlir::Location loc,
114                          const SmallVectorImpl<Value> &operands,
115                          const SmallVectorImpl<int32_t> &operandSegments) {
116   llvm::ArrayRef<mlir::Type> argTy;
117   Op op = builder.create<Op>(loc, argTy, operands);
118   op->setAttr(Op::getOperandSegmentSizeAttr(),
119               builder.getI32VectorAttr(operandSegments));
120   return op;
121 }
122 
123 static void genACC(Fortran::lower::AbstractConverter &converter,
124                    Fortran::lower::pft::Evaluation &eval,
125                    const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
126   Fortran::lower::StatementContext stmtCtx;
127   const auto &beginLoopDirective =
128       std::get<Fortran::parser::AccBeginLoopDirective>(loopConstruct.t);
129   const auto &loopDirective =
130       std::get<Fortran::parser::AccLoopDirective>(beginLoopDirective.t);
131 
132   if (loopDirective.v == llvm::acc::ACCD_loop) {
133     auto &firOpBuilder = converter.getFirOpBuilder();
134     auto currentLocation = converter.getCurrentLocation();
135 
136     // Add attribute extracted from clauses.
137     const auto &accClauseList =
138         std::get<Fortran::parser::AccClauseList>(beginLoopDirective.t);
139 
140     mlir::Value workerNum;
141     mlir::Value vectorLength;
142     mlir::Value gangNum;
143     mlir::Value gangStatic;
144     SmallVector<Value, 2> tileOperands, privateOperands, reductionOperands;
145     std::int64_t executionMapping = mlir::acc::OpenACCExecMapping::NONE;
146 
147     // Lower clauses values mapped to operands.
148     for (const auto &clause : accClauseList.v) {
149       if (const auto *gangClause =
150               std::get_if<Fortran::parser::AccClause::Gang>(&clause.u)) {
151         if (gangClause->v) {
152           const Fortran::parser::AccGangArgument &x = *gangClause->v;
153           if (const auto &gangNumValue =
154                   std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
155                       x.t)) {
156             gangNum = fir::getBase(converter.genExprValue(
157                 *Fortran::semantics::GetExpr(gangNumValue.value()), stmtCtx));
158           }
159           if (const auto &gangStaticValue =
160                   std::get<std::optional<Fortran::parser::AccSizeExpr>>(x.t)) {
161             const auto &expr =
162                 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
163                     gangStaticValue.value().t);
164             if (expr) {
165               gangStatic = fir::getBase(converter.genExprValue(
166                   *Fortran::semantics::GetExpr(*expr), stmtCtx));
167             } else {
168               // * was passed as value and will be represented as a -1 constant
169               // integer.
170               gangStatic = firOpBuilder.createIntegerConstant(
171                   currentLocation, firOpBuilder.getIntegerType(32),
172                   /* STAR */ -1);
173             }
174           }
175         }
176         executionMapping |= mlir::acc::OpenACCExecMapping::GANG;
177       } else if (const auto *workerClause =
178                      std::get_if<Fortran::parser::AccClause::Worker>(
179                          &clause.u)) {
180         if (workerClause->v) {
181           workerNum = fir::getBase(converter.genExprValue(
182               *Fortran::semantics::GetExpr(*workerClause->v), stmtCtx));
183         }
184         executionMapping |= mlir::acc::OpenACCExecMapping::WORKER;
185       } else if (const auto *vectorClause =
186                      std::get_if<Fortran::parser::AccClause::Vector>(
187                          &clause.u)) {
188         if (vectorClause->v) {
189           vectorLength = fir::getBase(converter.genExprValue(
190               *Fortran::semantics::GetExpr(*vectorClause->v), stmtCtx));
191         }
192         executionMapping |= mlir::acc::OpenACCExecMapping::VECTOR;
193       } else if (const auto *tileClause =
194                      std::get_if<Fortran::parser::AccClause::Tile>(&clause.u)) {
195         const Fortran::parser::AccTileExprList &accTileExprList = tileClause->v;
196         for (const auto &accTileExpr : accTileExprList.v) {
197           const auto &expr =
198               std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>(
199                   accTileExpr.t);
200           if (expr) {
201             tileOperands.push_back(fir::getBase(converter.genExprValue(
202                 *Fortran::semantics::GetExpr(*expr), stmtCtx)));
203           } else {
204             // * was passed as value and will be represented as a -1 constant
205             // integer.
206             mlir::Value tileStar = firOpBuilder.createIntegerConstant(
207                 currentLocation, firOpBuilder.getIntegerType(32),
208                 /* STAR */ -1);
209             tileOperands.push_back(tileStar);
210           }
211         }
212       } else if (const auto *privateClause =
213                      std::get_if<Fortran::parser::AccClause::Private>(
214                          &clause.u)) {
215         genObjectList(privateClause->v, converter, privateOperands);
216       }
217       // Reduction clause is left out for the moment as the clause will probably
218       // end up having its own operation.
219     }
220 
221     // Prepare the operand segement size attribute and the operands value range.
222     SmallVector<Value, 8> operands;
223     SmallVector<int32_t, 8> operandSegments;
224     addOperand(operands, operandSegments, gangNum);
225     addOperand(operands, operandSegments, gangStatic);
226     addOperand(operands, operandSegments, workerNum);
227     addOperand(operands, operandSegments, vectorLength);
228     addOperands(operands, operandSegments, tileOperands);
229     addOperands(operands, operandSegments, privateOperands);
230     addOperands(operands, operandSegments, reductionOperands);
231 
232     auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>(
233         firOpBuilder, currentLocation, operands, operandSegments);
234 
235     loopOp->setAttr(mlir::acc::LoopOp::getExecutionMappingAttrName(),
236                     firOpBuilder.getI64IntegerAttr(executionMapping));
237 
238     // Lower clauses mapped to attributes
239     for (const auto &clause : accClauseList.v) {
240       if (const auto *collapseClause =
241               std::get_if<Fortran::parser::AccClause::Collapse>(&clause.u)) {
242         const auto *expr = Fortran::semantics::GetExpr(collapseClause->v);
243         const auto collapseValue = Fortran::evaluate::ToInt64(*expr);
244         if (collapseValue) {
245           loopOp->setAttr(mlir::acc::LoopOp::getCollapseAttrName(),
246                           firOpBuilder.getI64IntegerAttr(*collapseValue));
247         }
248       } else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
249         loopOp->setAttr(mlir::acc::LoopOp::getSeqAttrName(),
250                         firOpBuilder.getUnitAttr());
251       } else if (std::get_if<Fortran::parser::AccClause::Independent>(
252                      &clause.u)) {
253         loopOp->setAttr(mlir::acc::LoopOp::getIndependentAttrName(),
254                         firOpBuilder.getUnitAttr());
255       } else if (std::get_if<Fortran::parser::AccClause::Auto>(&clause.u)) {
256         loopOp->setAttr(mlir::acc::LoopOp::getAutoAttrName(),
257                         firOpBuilder.getUnitAttr());
258       }
259     }
260   }
261 }
262 
263 static void
264 genACCParallelOp(Fortran::lower::AbstractConverter &converter,
265                  const Fortran::parser::AccClauseList &accClauseList) {
266   mlir::Value async;
267   mlir::Value numGangs;
268   mlir::Value numWorkers;
269   mlir::Value vectorLength;
270   mlir::Value ifCond;
271   mlir::Value selfCond;
272   SmallVector<Value, 2> waitOperands, reductionOperands, copyOperands,
273       copyinOperands, copyinReadonlyOperands, copyoutOperands,
274       copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands,
275       presentOperands, devicePtrOperands, attachOperands, privateOperands,
276       firstprivateOperands;
277 
278   // Async, wait and self clause have optional values but can be present with
279   // no value as well. When there is no value, the op has an attribute to
280   // represent the clause.
281   bool addAsyncAttr = false;
282   bool addWaitAttr = false;
283   bool addSelfAttr = false;
284 
285   auto &firOpBuilder = converter.getFirOpBuilder();
286   auto currentLocation = converter.getCurrentLocation();
287   Fortran::lower::StatementContext stmtCtx;
288 
289   // Lower clauses values mapped to operands.
290   // Keep track of each group of operands separatly as clauses can appear
291   // more than once.
292   for (const auto &clause : accClauseList.v) {
293     if (const auto *asyncClause =
294             std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
295       const auto &asyncClauseValue = asyncClause->v;
296       if (asyncClauseValue) { // async has a value.
297         async = fir::getBase(converter.genExprValue(
298             *Fortran::semantics::GetExpr(*asyncClauseValue), stmtCtx));
299       } else {
300         addAsyncAttr = true;
301       }
302     } else if (const auto *waitClause =
303                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
304       const auto &waitClauseValue = waitClause->v;
305       if (waitClauseValue) { // wait has a value.
306         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
307         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
308             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
309         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
310           Value v = fir::getBase(converter.genExprValue(
311               *Fortran::semantics::GetExpr(value), stmtCtx));
312           waitOperands.push_back(v);
313         }
314       } else {
315         addWaitAttr = true;
316       }
317     } else if (const auto *numGangsClause =
318                    std::get_if<Fortran::parser::AccClause::NumGangs>(
319                        &clause.u)) {
320       numGangs = fir::getBase(converter.genExprValue(
321           *Fortran::semantics::GetExpr(numGangsClause->v), stmtCtx));
322     } else if (const auto *numWorkersClause =
323                    std::get_if<Fortran::parser::AccClause::NumWorkers>(
324                        &clause.u)) {
325       numWorkers = fir::getBase(converter.genExprValue(
326           *Fortran::semantics::GetExpr(numWorkersClause->v), stmtCtx));
327     } else if (const auto *vectorLengthClause =
328                    std::get_if<Fortran::parser::AccClause::VectorLength>(
329                        &clause.u)) {
330       vectorLength = fir::getBase(converter.genExprValue(
331           *Fortran::semantics::GetExpr(vectorLengthClause->v), stmtCtx));
332     } else if (const auto *ifClause =
333                    std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
334       Value cond = fir::getBase(converter.genExprValue(
335           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
336       ifCond = firOpBuilder.createConvert(currentLocation,
337                                           firOpBuilder.getI1Type(), cond);
338     } else if (const auto *selfClause =
339                    std::get_if<Fortran::parser::AccClause::Self>(&clause.u)) {
340       const Fortran::parser::AccSelfClause &accSelfClause = selfClause->v;
341       if (const auto *optCondition =
342               std::get_if<std::optional<Fortran::parser::ScalarLogicalExpr>>(
343                   &accSelfClause.u)) {
344         if (*optCondition) {
345           Value cond = fir::getBase(converter.genExprValue(
346               *Fortran::semantics::GetExpr(*optCondition), stmtCtx));
347           selfCond = firOpBuilder.createConvert(currentLocation,
348                                                 firOpBuilder.getI1Type(), cond);
349         } else {
350           addSelfAttr = true;
351         }
352       }
353     } else if (const auto *copyClause =
354                    std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
355       genObjectList(copyClause->v, converter, copyOperands);
356     } else if (const auto *copyinClause =
357                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
358       genObjectListWithModifier<Fortran::parser::AccClause::Copyin>(
359           copyinClause, converter,
360           Fortran::parser::AccDataModifier::Modifier::ReadOnly,
361           copyinReadonlyOperands, copyinOperands);
362     } else if (const auto *copyoutClause =
363                    std::get_if<Fortran::parser::AccClause::Copyout>(
364                        &clause.u)) {
365       genObjectListWithModifier<Fortran::parser::AccClause::Copyout>(
366           copyoutClause, converter,
367           Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands,
368           copyoutOperands);
369     } else if (const auto *createClause =
370                    std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
371       genObjectListWithModifier<Fortran::parser::AccClause::Create>(
372           createClause, converter,
373           Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
374           createOperands);
375     } else if (const auto *noCreateClause =
376                    std::get_if<Fortran::parser::AccClause::NoCreate>(
377                        &clause.u)) {
378       genObjectList(noCreateClause->v, converter, noCreateOperands);
379     } else if (const auto *presentClause =
380                    std::get_if<Fortran::parser::AccClause::Present>(
381                        &clause.u)) {
382       genObjectList(presentClause->v, converter, presentOperands);
383     } else if (const auto *devicePtrClause =
384                    std::get_if<Fortran::parser::AccClause::Deviceptr>(
385                        &clause.u)) {
386       genObjectList(devicePtrClause->v, converter, devicePtrOperands);
387     } else if (const auto *attachClause =
388                    std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
389       genObjectList(attachClause->v, converter, attachOperands);
390     } else if (const auto *privateClause =
391                    std::get_if<Fortran::parser::AccClause::Private>(
392                        &clause.u)) {
393       genObjectList(privateClause->v, converter, privateOperands);
394     } else if (const auto *firstprivateClause =
395                    std::get_if<Fortran::parser::AccClause::Firstprivate>(
396                        &clause.u)) {
397       genObjectList(firstprivateClause->v, converter, firstprivateOperands);
398     }
399   }
400 
401   // Prepare the operand segement size attribute and the operands value range.
402   SmallVector<Value, 8> operands;
403   SmallVector<int32_t, 8> operandSegments;
404   addOperand(operands, operandSegments, async);
405   addOperands(operands, operandSegments, waitOperands);
406   addOperand(operands, operandSegments, numGangs);
407   addOperand(operands, operandSegments, numWorkers);
408   addOperand(operands, operandSegments, vectorLength);
409   addOperand(operands, operandSegments, ifCond);
410   addOperand(operands, operandSegments, selfCond);
411   addOperands(operands, operandSegments, reductionOperands);
412   addOperands(operands, operandSegments, copyOperands);
413   addOperands(operands, operandSegments, copyinOperands);
414   addOperands(operands, operandSegments, copyinReadonlyOperands);
415   addOperands(operands, operandSegments, copyoutOperands);
416   addOperands(operands, operandSegments, copyoutZeroOperands);
417   addOperands(operands, operandSegments, createOperands);
418   addOperands(operands, operandSegments, createZeroOperands);
419   addOperands(operands, operandSegments, noCreateOperands);
420   addOperands(operands, operandSegments, presentOperands);
421   addOperands(operands, operandSegments, devicePtrOperands);
422   addOperands(operands, operandSegments, attachOperands);
423   addOperands(operands, operandSegments, privateOperands);
424   addOperands(operands, operandSegments, firstprivateOperands);
425 
426   auto parallelOp = createRegionOp<mlir::acc::ParallelOp, mlir::acc::YieldOp>(
427       firOpBuilder, currentLocation, operands, operandSegments);
428 
429   if (addAsyncAttr)
430     parallelOp->setAttr(mlir::acc::ParallelOp::getAsyncAttrName(),
431                         firOpBuilder.getUnitAttr());
432   if (addWaitAttr)
433     parallelOp->setAttr(mlir::acc::ParallelOp::getWaitAttrName(),
434                         firOpBuilder.getUnitAttr());
435   if (addSelfAttr)
436     parallelOp->setAttr(mlir::acc::ParallelOp::getSelfAttrName(),
437                         firOpBuilder.getUnitAttr());
438 }
439 
440 static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
441                          const Fortran::parser::AccClauseList &accClauseList) {
442   mlir::Value ifCond;
443   SmallVector<Value, 2> copyOperands, copyinOperands, copyinReadonlyOperands,
444       copyoutOperands, copyoutZeroOperands, createOperands, createZeroOperands,
445       noCreateOperands, presentOperands, deviceptrOperands, attachOperands;
446 
447   auto &firOpBuilder = converter.getFirOpBuilder();
448   auto currentLocation = converter.getCurrentLocation();
449   Fortran::lower::StatementContext stmtCtx;
450 
451   // Lower clauses values mapped to operands.
452   // Keep track of each group of operands separatly as clauses can appear
453   // more than once.
454   for (const auto &clause : accClauseList.v) {
455     if (const auto *ifClause =
456             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
457       Value cond = fir::getBase(converter.genExprValue(
458           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
459       ifCond = firOpBuilder.createConvert(currentLocation,
460                                           firOpBuilder.getI1Type(), cond);
461     } else if (const auto *copyClause =
462                    std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
463       genObjectList(copyClause->v, converter, copyOperands);
464     } else if (const auto *copyinClause =
465                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
466       genObjectListWithModifier<Fortran::parser::AccClause::Copyin>(
467           copyinClause, converter,
468           Fortran::parser::AccDataModifier::Modifier::ReadOnly,
469           copyinReadonlyOperands, copyinOperands);
470     } else if (const auto *copyoutClause =
471                    std::get_if<Fortran::parser::AccClause::Copyout>(
472                        &clause.u)) {
473       genObjectListWithModifier<Fortran::parser::AccClause::Copyout>(
474           copyoutClause, converter,
475           Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands,
476           copyoutOperands);
477     } else if (const auto *createClause =
478                    std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
479       genObjectListWithModifier<Fortran::parser::AccClause::Create>(
480           createClause, converter,
481           Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
482           createOperands);
483     } else if (const auto *noCreateClause =
484                    std::get_if<Fortran::parser::AccClause::NoCreate>(
485                        &clause.u)) {
486       genObjectList(noCreateClause->v, converter, noCreateOperands);
487     } else if (const auto *presentClause =
488                    std::get_if<Fortran::parser::AccClause::Present>(
489                        &clause.u)) {
490       genObjectList(presentClause->v, converter, presentOperands);
491     } else if (const auto *deviceptrClause =
492                    std::get_if<Fortran::parser::AccClause::Deviceptr>(
493                        &clause.u)) {
494       genObjectList(deviceptrClause->v, converter, deviceptrOperands);
495     } else if (const auto *attachClause =
496                    std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
497       genObjectList(attachClause->v, converter, attachOperands);
498     }
499   }
500 
501   // Prepare the operand segement size attribute and the operands value range.
502   SmallVector<Value, 8> operands;
503   SmallVector<int32_t, 8> operandSegments;
504   addOperand(operands, operandSegments, ifCond);
505   addOperands(operands, operandSegments, copyOperands);
506   addOperands(operands, operandSegments, copyinOperands);
507   addOperands(operands, operandSegments, copyinReadonlyOperands);
508   addOperands(operands, operandSegments, copyoutOperands);
509   addOperands(operands, operandSegments, copyoutZeroOperands);
510   addOperands(operands, operandSegments, createOperands);
511   addOperands(operands, operandSegments, createZeroOperands);
512   addOperands(operands, operandSegments, noCreateOperands);
513   addOperands(operands, operandSegments, presentOperands);
514   addOperands(operands, operandSegments, deviceptrOperands);
515   addOperands(operands, operandSegments, attachOperands);
516 
517   createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>(
518       firOpBuilder, currentLocation, operands, operandSegments);
519 }
520 
521 static void
522 genACC(Fortran::lower::AbstractConverter &converter,
523        Fortran::lower::pft::Evaluation &eval,
524        const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
525   const auto &beginBlockDirective =
526       std::get<Fortran::parser::AccBeginBlockDirective>(blockConstruct.t);
527   const auto &blockDirective =
528       std::get<Fortran::parser::AccBlockDirective>(beginBlockDirective.t);
529   const auto &accClauseList =
530       std::get<Fortran::parser::AccClauseList>(beginBlockDirective.t);
531 
532   if (blockDirective.v == llvm::acc::ACCD_parallel) {
533     genACCParallelOp(converter, accClauseList);
534   } else if (blockDirective.v == llvm::acc::ACCD_data) {
535     genACCDataOp(converter, accClauseList);
536   }
537 }
538 
539 static void
540 genACCEnterDataOp(Fortran::lower::AbstractConverter &converter,
541                   const Fortran::parser::AccClauseList &accClauseList) {
542   mlir::Value ifCond, async, waitDevnum;
543   SmallVector<Value, 2> copyinOperands, createOperands, createZeroOperands,
544       attachOperands, waitOperands;
545 
546   // Async, wait and self clause have optional values but can be present with
547   // no value as well. When there is no value, the op has an attribute to
548   // represent the clause.
549   bool addAsyncAttr = false;
550   bool addWaitAttr = false;
551 
552   auto &firOpBuilder = converter.getFirOpBuilder();
553   auto currentLocation = converter.getCurrentLocation();
554   Fortran::lower::StatementContext stmtCtx;
555 
556   // Lower clauses values mapped to operands.
557   // Keep track of each group of operands separatly as clauses can appear
558   // more than once.
559   for (const auto &clause : accClauseList.v) {
560     if (const auto *ifClause =
561             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
562       mlir::Value cond = fir::getBase(converter.genExprValue(
563           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
564       ifCond = firOpBuilder.createConvert(currentLocation,
565                                           firOpBuilder.getI1Type(), cond);
566     } else if (const auto *asyncClause =
567                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
568       const auto &asyncClauseValue = asyncClause->v;
569       if (asyncClauseValue) { // async has a value.
570         async = fir::getBase(converter.genExprValue(
571             *Fortran::semantics::GetExpr(*asyncClauseValue), stmtCtx));
572       } else {
573         addAsyncAttr = true;
574       }
575     } else if (const auto *waitClause =
576                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
577       const auto &waitClauseValue = waitClause->v;
578       if (waitClauseValue) { // wait has a value.
579         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
580         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
581             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
582         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
583           mlir::Value v = fir::getBase(converter.genExprValue(
584               *Fortran::semantics::GetExpr(value), stmtCtx));
585           waitOperands.push_back(v);
586         }
587 
588         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
589             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
590         if (waitDevnumValue)
591           waitDevnum = fir::getBase(converter.genExprValue(
592               *Fortran::semantics::GetExpr(*waitDevnumValue), stmtCtx));
593       } else {
594         addWaitAttr = true;
595       }
596     } else if (const auto *copyinClause =
597                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
598       const Fortran::parser::AccObjectListWithModifier &listWithModifier =
599           copyinClause->v;
600       const Fortran::parser::AccObjectList &accObjectList =
601           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
602       genObjectList(accObjectList, converter, copyinOperands);
603     } else if (const auto *createClause =
604                    std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
605       genObjectListWithModifier<Fortran::parser::AccClause::Create>(
606           createClause, converter,
607           Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
608           createOperands);
609     } else if (const auto *attachClause =
610                    std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
611       genObjectList(attachClause->v, converter, attachOperands);
612     } else {
613       llvm::report_fatal_error(
614           "Unknown clause in ENTER DATA directive lowering");
615     }
616   }
617 
618   // Prepare the operand segement size attribute and the operands value range.
619   SmallVector<mlir::Value, 16> operands;
620   SmallVector<int32_t, 8> operandSegments;
621   addOperand(operands, operandSegments, ifCond);
622   addOperand(operands, operandSegments, async);
623   addOperand(operands, operandSegments, waitDevnum);
624   addOperands(operands, operandSegments, waitOperands);
625   addOperands(operands, operandSegments, copyinOperands);
626   addOperands(operands, operandSegments, createOperands);
627   addOperands(operands, operandSegments, createZeroOperands);
628   addOperands(operands, operandSegments, attachOperands);
629 
630   auto enterDataOp = createSimpleOp<mlir::acc::EnterDataOp>(
631       firOpBuilder, currentLocation, operands, operandSegments);
632 
633   if (addAsyncAttr)
634     enterDataOp.asyncAttr(firOpBuilder.getUnitAttr());
635   if (addWaitAttr)
636     enterDataOp.waitAttr(firOpBuilder.getUnitAttr());
637 }
638 
639 static void
640 genACCExitDataOp(Fortran::lower::AbstractConverter &converter,
641                  const Fortran::parser::AccClauseList &accClauseList) {
642   mlir::Value ifCond, async, waitDevnum;
643   SmallVector<Value, 2> copyoutOperands, deleteOperands, detachOperands,
644       waitOperands;
645 
646   // Async and wait clause have optional values but can be present with
647   // no value as well. When there is no value, the op has an attribute to
648   // represent the clause.
649   bool addAsyncAttr = false;
650   bool addWaitAttr = false;
651   bool addFinalizeAttr = false;
652 
653   auto &firOpBuilder = converter.getFirOpBuilder();
654   auto currentLocation = converter.getCurrentLocation();
655   Fortran::lower::StatementContext stmtCtx;
656 
657   // Lower clauses values mapped to operands.
658   // Keep track of each group of operands separatly as clauses can appear
659   // more than once.
660   for (const auto &clause : accClauseList.v) {
661     if (const auto *ifClause =
662             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
663       Value cond = fir::getBase(converter.genExprValue(
664           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
665       ifCond = firOpBuilder.createConvert(currentLocation,
666                                           firOpBuilder.getI1Type(), cond);
667     } else if (const auto *asyncClause =
668                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
669       const auto &asyncClauseValue = asyncClause->v;
670       if (asyncClauseValue) { // async has a value.
671         async = fir::getBase(converter.genExprValue(
672             *Fortran::semantics::GetExpr(*asyncClauseValue), stmtCtx));
673       } else {
674         addAsyncAttr = true;
675       }
676     } else if (const auto *waitClause =
677                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
678       const auto &waitClauseValue = waitClause->v;
679       if (waitClauseValue) { // wait has a value.
680         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
681         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
682             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
683         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
684           Value v = fir::getBase(converter.genExprValue(
685               *Fortran::semantics::GetExpr(value), stmtCtx));
686           waitOperands.push_back(v);
687         }
688 
689         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
690             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
691         if (waitDevnumValue)
692           waitDevnum = fir::getBase(converter.genExprValue(
693               *Fortran::semantics::GetExpr(*waitDevnumValue), stmtCtx));
694       } else {
695         addWaitAttr = true;
696       }
697     } else if (const auto *copyoutClause =
698                    std::get_if<Fortran::parser::AccClause::Copyout>(
699                        &clause.u)) {
700       const Fortran::parser::AccObjectListWithModifier &listWithModifier =
701           copyoutClause->v;
702       const Fortran::parser::AccObjectList &accObjectList =
703           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
704       genObjectList(accObjectList, converter, copyoutOperands);
705     } else if (const auto *deleteClause =
706                    std::get_if<Fortran::parser::AccClause::Delete>(&clause.u)) {
707       genObjectList(deleteClause->v, converter, deleteOperands);
708     } else if (const auto *detachClause =
709                    std::get_if<Fortran::parser::AccClause::Detach>(&clause.u)) {
710       genObjectList(detachClause->v, converter, detachOperands);
711     } else if (std::get_if<Fortran::parser::AccClause::Finalize>(&clause.u)) {
712       addFinalizeAttr = true;
713     }
714   }
715 
716   // Prepare the operand segement size attribute and the operands value range.
717   SmallVector<mlir::Value, 14> operands;
718   SmallVector<int32_t, 7> operandSegments;
719   addOperand(operands, operandSegments, ifCond);
720   addOperand(operands, operandSegments, async);
721   addOperand(operands, operandSegments, waitDevnum);
722   addOperands(operands, operandSegments, waitOperands);
723   addOperands(operands, operandSegments, copyoutOperands);
724   addOperands(operands, operandSegments, deleteOperands);
725   addOperands(operands, operandSegments, detachOperands);
726 
727   auto exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
728       firOpBuilder, currentLocation, operands, operandSegments);
729 
730   if (addAsyncAttr)
731     exitDataOp.asyncAttr(firOpBuilder.getUnitAttr());
732   if (addWaitAttr)
733     exitDataOp.waitAttr(firOpBuilder.getUnitAttr());
734   if (addFinalizeAttr)
735     exitDataOp.finalizeAttr(firOpBuilder.getUnitAttr());
736 }
737 
738 template <typename Op>
739 static void
740 genACCInitShutdownOp(Fortran::lower::AbstractConverter &converter,
741                      const Fortran::parser::AccClauseList &accClauseList) {
742   mlir::Value ifCond, deviceNum;
743   SmallVector<Value, 2> deviceTypeOperands;
744 
745   auto &firOpBuilder = converter.getFirOpBuilder();
746   auto currentLocation = converter.getCurrentLocation();
747   Fortran::lower::StatementContext stmtCtx;
748 
749   // Lower clauses values mapped to operands.
750   // Keep track of each group of operands separatly as clauses can appear
751   // more than once.
752   for (const auto &clause : accClauseList.v) {
753     if (const auto *ifClause =
754             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
755       mlir::Value cond = fir::getBase(converter.genExprValue(
756           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
757       ifCond = firOpBuilder.createConvert(currentLocation,
758                                           firOpBuilder.getI1Type(), cond);
759     } else if (const auto *deviceNumClause =
760                    std::get_if<Fortran::parser::AccClause::DeviceNum>(
761                        &clause.u)) {
762       deviceNum = fir::getBase(converter.genExprValue(
763           *Fortran::semantics::GetExpr(deviceNumClause->v), stmtCtx));
764     } else if (const auto *deviceTypeClause =
765                    std::get_if<Fortran::parser::AccClause::DeviceType>(
766                        &clause.u)) {
767 
768       const auto &deviceTypeValue = deviceTypeClause->v;
769       if (deviceTypeValue) {
770         for (const auto &scalarIntExpr : *deviceTypeValue) {
771           mlir::Value expr = fir::getBase(converter.genExprValue(
772               *Fortran::semantics::GetExpr(scalarIntExpr), stmtCtx));
773           deviceTypeOperands.push_back(expr);
774         }
775       } else {
776         // * was passed as value and will be represented as a -1 constant
777         // integer.
778         mlir::Value star = firOpBuilder.createIntegerConstant(
779             currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
780         deviceTypeOperands.push_back(star);
781       }
782     }
783   }
784 
785   // Prepare the operand segement size attribute and the operands value range.
786   SmallVector<mlir::Value, 6> operands;
787   SmallVector<int32_t, 3> operandSegments;
788   addOperands(operands, operandSegments, deviceTypeOperands);
789   addOperand(operands, operandSegments, deviceNum);
790   addOperand(operands, operandSegments, ifCond);
791 
792   createSimpleOp<Op>(firOpBuilder, currentLocation, operands, operandSegments);
793 }
794 
795 static void
796 genACCUpdateOp(Fortran::lower::AbstractConverter &converter,
797                const Fortran::parser::AccClauseList &accClauseList) {
798   mlir::Value ifCond, async, waitDevnum;
799   SmallVector<Value, 2> hostOperands, deviceOperands, waitOperands,
800       deviceTypeOperands;
801 
802   // Async and wait clause have optional values but can be present with
803   // no value as well. When there is no value, the op has an attribute to
804   // represent the clause.
805   bool addAsyncAttr = false;
806   bool addWaitAttr = false;
807   bool addIfPresentAttr = false;
808 
809   auto &firOpBuilder = converter.getFirOpBuilder();
810   auto currentLocation = converter.getCurrentLocation();
811   Fortran::lower::StatementContext stmtCtx;
812 
813   // Lower clauses values mapped to operands.
814   // Keep track of each group of operands separatly as clauses can appear
815   // more than once.
816   for (const auto &clause : accClauseList.v) {
817     if (const auto *ifClause =
818             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
819       mlir::Value cond = fir::getBase(converter.genExprValue(
820           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
821       ifCond = firOpBuilder.createConvert(currentLocation,
822                                           firOpBuilder.getI1Type(), cond);
823     } else if (const auto *asyncClause =
824                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
825       const auto &asyncClauseValue = asyncClause->v;
826       if (asyncClauseValue) { // async has a value.
827         async = fir::getBase(converter.genExprValue(
828             *Fortran::semantics::GetExpr(*asyncClauseValue), stmtCtx));
829       } else {
830         addAsyncAttr = true;
831       }
832     } else if (const auto *waitClause =
833                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
834       const auto &waitClauseValue = waitClause->v;
835       if (waitClauseValue) { // wait has a value.
836         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
837         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
838             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
839         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
840           mlir::Value v = fir::getBase(converter.genExprValue(
841               *Fortran::semantics::GetExpr(value), stmtCtx));
842           waitOperands.push_back(v);
843         }
844 
845         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
846             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
847         if (waitDevnumValue)
848           waitDevnum = fir::getBase(converter.genExprValue(
849               *Fortran::semantics::GetExpr(*waitDevnumValue), stmtCtx));
850       } else {
851         addWaitAttr = true;
852       }
853     } else if (const auto *deviceTypeClause =
854                    std::get_if<Fortran::parser::AccClause::DeviceType>(
855                        &clause.u)) {
856 
857       const auto &deviceTypeValue = deviceTypeClause->v;
858       if (deviceTypeValue) {
859         for (const auto &scalarIntExpr : *deviceTypeValue) {
860           mlir::Value expr = fir::getBase(converter.genExprValue(
861               *Fortran::semantics::GetExpr(scalarIntExpr), stmtCtx));
862           deviceTypeOperands.push_back(expr);
863         }
864       } else {
865         // * was passed as value and will be represented as a -1 constant
866         // integer.
867         mlir::Value star = firOpBuilder.createIntegerConstant(
868             currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
869         deviceTypeOperands.push_back(star);
870       }
871     } else if (const auto *hostClause =
872                    std::get_if<Fortran::parser::AccClause::Host>(&clause.u)) {
873       genObjectList(hostClause->v, converter, hostOperands);
874     } else if (const auto *deviceClause =
875                    std::get_if<Fortran::parser::AccClause::Device>(&clause.u)) {
876       genObjectList(deviceClause->v, converter, deviceOperands);
877     }
878   }
879 
880   // Prepare the operand segement size attribute and the operands value range.
881   SmallVector<mlir::Value, 14> operands;
882   SmallVector<int32_t, 7> operandSegments;
883   addOperand(operands, operandSegments, async);
884   addOperand(operands, operandSegments, waitDevnum);
885   addOperands(operands, operandSegments, waitOperands);
886   addOperands(operands, operandSegments, deviceTypeOperands);
887   addOperand(operands, operandSegments, ifCond);
888   addOperands(operands, operandSegments, hostOperands);
889   addOperands(operands, operandSegments, deviceOperands);
890 
891   auto updateOp = createSimpleOp<mlir::acc::UpdateOp>(
892       firOpBuilder, currentLocation, operands, operandSegments);
893 
894   if (addAsyncAttr)
895     updateOp.asyncAttr(firOpBuilder.getUnitAttr());
896   if (addWaitAttr)
897     updateOp.waitAttr(firOpBuilder.getUnitAttr());
898   if (addIfPresentAttr)
899     updateOp.ifPresentAttr(firOpBuilder.getUnitAttr());
900 }
901 
902 static void
903 genACC(Fortran::lower::AbstractConverter &converter,
904        Fortran::lower::pft::Evaluation &eval,
905        const Fortran::parser::OpenACCStandaloneConstruct &standaloneConstruct) {
906   const auto &standaloneDirective =
907       std::get<Fortran::parser::AccStandaloneDirective>(standaloneConstruct.t);
908   const auto &accClauseList =
909       std::get<Fortran::parser::AccClauseList>(standaloneConstruct.t);
910 
911   if (standaloneDirective.v == llvm::acc::Directive::ACCD_enter_data) {
912     genACCEnterDataOp(converter, accClauseList);
913   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_exit_data) {
914     genACCExitDataOp(converter, accClauseList);
915   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_init) {
916     genACCInitShutdownOp<mlir::acc::InitOp>(converter, accClauseList);
917   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_shutdown) {
918     genACCInitShutdownOp<mlir::acc::ShutdownOp>(converter, accClauseList);
919   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_set) {
920     TODO(converter.getCurrentLocation(),
921          "OpenACC set directive not lowered yet!");
922   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_update) {
923     genACCUpdateOp(converter, accClauseList);
924   }
925 }
926 
927 static void genACC(Fortran::lower::AbstractConverter &converter,
928                    Fortran::lower::pft::Evaluation &eval,
929                    const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
930 
931   const auto &waitArgument =
932       std::get<std::optional<Fortran::parser::AccWaitArgument>>(
933           waitConstruct.t);
934   const auto &accClauseList =
935       std::get<Fortran::parser::AccClauseList>(waitConstruct.t);
936 
937   mlir::Value ifCond, waitDevnum, async;
938   SmallVector<mlir::Value, 2> waitOperands;
939 
940   // Async clause have optional values but can be present with
941   // no value as well. When there is no value, the op has an attribute to
942   // represent the clause.
943   bool addAsyncAttr = false;
944 
945   auto &firOpBuilder = converter.getFirOpBuilder();
946   auto currentLocation = converter.getCurrentLocation();
947   Fortran::lower::StatementContext stmtCtx;
948 
949   if (waitArgument) { // wait has a value.
950     const Fortran::parser::AccWaitArgument &waitArg = *waitArgument;
951     const std::list<Fortran::parser::ScalarIntExpr> &waitList =
952         std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
953     for (const Fortran::parser::ScalarIntExpr &value : waitList) {
954       mlir::Value v = fir::getBase(
955           converter.genExprValue(*Fortran::semantics::GetExpr(value), stmtCtx));
956       waitOperands.push_back(v);
957     }
958 
959     const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
960         std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
961     if (waitDevnumValue)
962       waitDevnum = fir::getBase(converter.genExprValue(
963           *Fortran::semantics::GetExpr(*waitDevnumValue), stmtCtx));
964   }
965 
966   // Lower clauses values mapped to operands.
967   // Keep track of each group of operands separatly as clauses can appear
968   // more than once.
969   for (const auto &clause : accClauseList.v) {
970     if (const auto *ifClause =
971             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
972       mlir::Value cond = fir::getBase(converter.genExprValue(
973           *Fortran::semantics::GetExpr(ifClause->v), stmtCtx));
974       ifCond = firOpBuilder.createConvert(currentLocation,
975                                           firOpBuilder.getI1Type(), cond);
976     } else if (const auto *asyncClause =
977                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
978       const auto &asyncClauseValue = asyncClause->v;
979       if (asyncClauseValue) { // async has a value.
980         async = fir::getBase(converter.genExprValue(
981             *Fortran::semantics::GetExpr(*asyncClauseValue), stmtCtx));
982       } else {
983         addAsyncAttr = true;
984       }
985     }
986   }
987 
988   // Prepare the operand segement size attribute and the operands value range.
989   SmallVector<mlir::Value, 8> operands;
990   SmallVector<int32_t, 4> operandSegments;
991   addOperands(operands, operandSegments, waitOperands);
992   addOperand(operands, operandSegments, async);
993   addOperand(operands, operandSegments, waitDevnum);
994   addOperand(operands, operandSegments, ifCond);
995 
996   auto waitOp = createSimpleOp<mlir::acc::WaitOp>(firOpBuilder, currentLocation,
997                                                   operands, operandSegments);
998 
999   if (addAsyncAttr)
1000     waitOp.asyncAttr(firOpBuilder.getUnitAttr());
1001 }
1002 
1003 void Fortran::lower::genOpenACCConstruct(
1004     Fortran::lower::AbstractConverter &converter,
1005     Fortran::lower::pft::Evaluation &eval,
1006     const Fortran::parser::OpenACCConstruct &accConstruct) {
1007 
1008   std::visit(
1009       common::visitors{
1010           [&](const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
1011             genACC(converter, eval, blockConstruct);
1012           },
1013           [&](const Fortran::parser::OpenACCCombinedConstruct
1014                   &combinedConstruct) {
1015             TODO(converter.getCurrentLocation(),
1016                  "OpenACC Combined construct not lowered yet!");
1017           },
1018           [&](const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
1019             genACC(converter, eval, loopConstruct);
1020           },
1021           [&](const Fortran::parser::OpenACCStandaloneConstruct
1022                   &standaloneConstruct) {
1023             genACC(converter, eval, standaloneConstruct);
1024           },
1025           [&](const Fortran::parser::OpenACCRoutineConstruct
1026                   &routineConstruct) {
1027             TODO(converter.getCurrentLocation(),
1028                  "OpenACC Routine construct not lowered yet!");
1029           },
1030           [&](const Fortran::parser::OpenACCCacheConstruct &cacheConstruct) {
1031             TODO(converter.getCurrentLocation(),
1032                  "OpenACC Cache construct not lowered yet!");
1033           },
1034           [&](const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
1035             genACC(converter, eval, waitConstruct);
1036           },
1037           [&](const Fortran::parser::OpenACCAtomicConstruct &atomicConstruct) {
1038             TODO(converter.getCurrentLocation(),
1039                  "OpenACC Atomic construct not lowered yet!");
1040           },
1041       },
1042       accConstruct.u);
1043 }
1044