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