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