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/FIRBuilder.h"
17 #include "flang/Lower/PFTBuilder.h"
18 #include "flang/Lower/Support/BoxValue.h"
19 #include "flang/Lower/Todo.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 *
getDesignatorNameIfDataRef(const Fortran::parser::Designator & designator)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 
genObjectList(const Fortran::parser::AccObjectList & objectList,Fortran::lower::AbstractConverter & converter,SmallVectorImpl<Value> & operands)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
genObjectListWithModifier(const Clause * x,Fortran::lower::AbstractConverter & converter,Fortran::parser::AccDataModifier::Modifier mod,SmallVectorImpl<Value> & operandsWithModifier,SmallVectorImpl<Value> & operands)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 
addOperands(SmallVectorImpl<Value> & operands,SmallVectorImpl<int32_t> & operandSegments,const SmallVectorImpl<Value> & clauseOperands)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 
addOperand(SmallVectorImpl<Value> & operands,SmallVectorImpl<int32_t> & operandSegments,const Value & clauseOperand)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>
createRegionOp(Fortran::lower::FirOpBuilder & builder,mlir::Location loc,const SmallVectorImpl<Value> & operands,const SmallVectorImpl<int32_t> & operandSegments)90 static Op createRegionOp(Fortran::lower::FirOpBuilder &builder,
91                          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>
createSimpleOp(Fortran::lower::FirOpBuilder & builder,mlir::Location loc,const SmallVectorImpl<Value> & operands,const SmallVectorImpl<int32_t> & operandSegments)111 static Op createSimpleOp(Fortran::lower::FirOpBuilder &builder,
112                          mlir::Location loc,
113                          const SmallVectorImpl<Value> &operands,
114                          const SmallVectorImpl<int32_t> &operandSegments) {
115   llvm::ArrayRef<mlir::Type> argTy;
116   Op op = builder.create<Op>(loc, argTy, operands);
117   op.setAttr(Op::getOperandSegmentSizeAttr(),
118              builder.getI32VectorAttr(operandSegments));
119   return op;
120 }
121 
genACC(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenACCLoopConstruct & loopConstruct)122 static void genACC(Fortran::lower::AbstractConverter &converter,
123                    Fortran::lower::pft::Evaluation &eval,
124                    const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
125 
126   const auto &beginLoopDirective =
127       std::get<Fortran::parser::AccBeginLoopDirective>(loopConstruct.t);
128   const auto &loopDirective =
129       std::get<Fortran::parser::AccLoopDirective>(beginLoopDirective.t);
130 
131   if (loopDirective.v == llvm::acc::ACCD_loop) {
132     auto &firOpBuilder = converter.getFirOpBuilder();
133     auto currentLocation = converter.getCurrentLocation();
134 
135     // Add attribute extracted from clauses.
136     const auto &accClauseList =
137         std::get<Fortran::parser::AccClauseList>(beginLoopDirective.t);
138 
139     mlir::Value workerNum;
140     mlir::Value vectorLength;
141     mlir::Value gangNum;
142     mlir::Value gangStatic;
143     SmallVector<Value, 2> tileOperands, privateOperands, reductionOperands;
144     std::int64_t executionMapping = mlir::acc::OpenACCExecMapping::NONE;
145 
146     // Lower clauses values mapped to operands.
147     for (const auto &clause : accClauseList.v) {
148       if (const auto *gangClause =
149               std::get_if<Fortran::parser::AccClause::Gang>(&clause.u)) {
150         if (gangClause->v) {
151           const Fortran::parser::AccGangArgument &x = *gangClause->v;
152           if (const auto &gangNumValue =
153                   std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
154                       x.t)) {
155             gangNum = fir::getBase(converter.genExprValue(
156                 *Fortran::semantics::GetExpr(gangNumValue.value())));
157           }
158           if (const auto &gangStaticValue =
159                   std::get<std::optional<Fortran::parser::AccSizeExpr>>(x.t)) {
160             const auto &expr =
161                 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
162                     gangStaticValue.value().t);
163             if (expr) {
164               gangStatic = fir::getBase(
165                   converter.genExprValue(*Fortran::semantics::GetExpr(*expr)));
166             } else {
167               // * was passed as value and will be represented as a -1 constant
168               // integer.
169               gangStatic = firOpBuilder.createIntegerConstant(
170                   currentLocation, firOpBuilder.getIntegerType(32),
171                   /* STAR */ -1);
172             }
173           }
174         }
175         executionMapping |= mlir::acc::OpenACCExecMapping::GANG;
176       } else if (const auto *workerClause =
177                      std::get_if<Fortran::parser::AccClause::Worker>(
178                          &clause.u)) {
179         if (workerClause->v) {
180           workerNum = fir::getBase(converter.genExprValue(
181               *Fortran::semantics::GetExpr(*workerClause->v)));
182         }
183         executionMapping |= mlir::acc::OpenACCExecMapping::WORKER;
184       } else if (const auto *vectorClause =
185                      std::get_if<Fortran::parser::AccClause::Vector>(
186                          &clause.u)) {
187         if (vectorClause->v) {
188           vectorLength = fir::getBase(converter.genExprValue(
189               *Fortran::semantics::GetExpr(*vectorClause->v)));
190         }
191         executionMapping |= mlir::acc::OpenACCExecMapping::VECTOR;
192       } else if (const auto *tileClause =
193                      std::get_if<Fortran::parser::AccClause::Tile>(&clause.u)) {
194         const Fortran::parser::AccTileExprList &accTileExprList = tileClause->v;
195         for (const auto &accTileExpr : accTileExprList.v) {
196           const auto &expr =
197               std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>(
198                   accTileExpr.t);
199           if (expr) {
200             tileOperands.push_back(fir::getBase(
201                 converter.genExprValue(*Fortran::semantics::GetExpr(*expr))));
202           } else {
203             // * was passed as value and will be represented as a -1 constant
204             // integer.
205             mlir::Value tileStar = firOpBuilder.createIntegerConstant(
206                 currentLocation, firOpBuilder.getIntegerType(32),
207                 /* STAR */ -1);
208             tileOperands.push_back(tileStar);
209           }
210         }
211       } else if (const auto *privateClause =
212                      std::get_if<Fortran::parser::AccClause::Private>(
213                          &clause.u)) {
214         genObjectList(privateClause->v, converter, privateOperands);
215       }
216       // Reduction clause is left out for the moment as the clause will probably
217       // end up having its own operation.
218     }
219 
220     // Prepare the operand segement size attribute and the operands value range.
221     SmallVector<Value, 8> operands;
222     SmallVector<int32_t, 8> operandSegments;
223     addOperand(operands, operandSegments, gangNum);
224     addOperand(operands, operandSegments, gangStatic);
225     addOperand(operands, operandSegments, workerNum);
226     addOperand(operands, operandSegments, vectorLength);
227     addOperands(operands, operandSegments, tileOperands);
228     addOperands(operands, operandSegments, privateOperands);
229     addOperands(operands, operandSegments, reductionOperands);
230 
231     auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>(
232         firOpBuilder, currentLocation, operands, operandSegments);
233 
234     loopOp.setAttr(mlir::acc::LoopOp::getExecutionMappingAttrName(),
235                    firOpBuilder.getI64IntegerAttr(executionMapping));
236 
237     // Lower clauses mapped to attributes
238     for (const auto &clause : accClauseList.v) {
239       if (const auto *collapseClause =
240               std::get_if<Fortran::parser::AccClause::Collapse>(&clause.u)) {
241         const auto *expr = Fortran::semantics::GetExpr(collapseClause->v);
242         const auto collapseValue = Fortran::evaluate::ToInt64(*expr);
243         if (collapseValue) {
244           loopOp.setAttr(mlir::acc::LoopOp::getCollapseAttrName(),
245                          firOpBuilder.getI64IntegerAttr(*collapseValue));
246         }
247       } else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
248         loopOp.setAttr(mlir::acc::LoopOp::getSeqAttrName(),
249                        firOpBuilder.getUnitAttr());
250       } else if (std::get_if<Fortran::parser::AccClause::Independent>(
251                      &clause.u)) {
252         loopOp.setAttr(mlir::acc::LoopOp::getIndependentAttrName(),
253                        firOpBuilder.getUnitAttr());
254       } else if (std::get_if<Fortran::parser::AccClause::Auto>(&clause.u)) {
255         loopOp.setAttr(mlir::acc::LoopOp::getAutoAttrName(),
256                        firOpBuilder.getUnitAttr());
257       }
258     }
259   }
260 }
261 
262 static void
genACCParallelOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)263 genACCParallelOp(Fortran::lower::AbstractConverter &converter,
264                  const Fortran::parser::AccClauseList &accClauseList) {
265   mlir::Value async;
266   mlir::Value numGangs;
267   mlir::Value numWorkers;
268   mlir::Value vectorLength;
269   mlir::Value ifCond;
270   mlir::Value selfCond;
271   SmallVector<Value, 2> waitOperands, reductionOperands, copyOperands,
272       copyinOperands, copyinReadonlyOperands, copyoutOperands,
273       copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands,
274       presentOperands, devicePtrOperands, attachOperands, privateOperands,
275       firstprivateOperands;
276 
277   // Async, wait and self clause have optional values but can be present with
278   // no value as well. When there is no value, the op has an attribute to
279   // represent the clause.
280   bool addAsyncAttr = false;
281   bool addWaitAttr = false;
282   bool addSelfAttr = false;
283 
284   auto &firOpBuilder = converter.getFirOpBuilder();
285   auto currentLocation = converter.getCurrentLocation();
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)));
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(
309               converter.genExprValue(*Fortran::semantics::GetExpr(value)));
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)));
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)));
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)));
330     } else if (const auto *ifClause =
331                    std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
332       Value cond = fir::getBase(
333           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
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)));
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 
genACCDataOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)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 
448   // Lower clauses values mapped to operands.
449   // Keep track of each group of operands separatly as clauses can appear
450   // more than once.
451   for (const auto &clause : accClauseList.v) {
452     if (const auto *ifClause =
453             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
454       Value cond = fir::getBase(
455           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
456       ifCond = firOpBuilder.createConvert(currentLocation,
457                                           firOpBuilder.getI1Type(), cond);
458     } else if (const auto *copyClause =
459                    std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
460       genObjectList(copyClause->v, converter, copyOperands);
461     } else if (const auto *copyinClause =
462                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
463       genObjectListWithModifier<Fortran::parser::AccClause::Copyin>(
464           copyinClause, converter,
465           Fortran::parser::AccDataModifier::Modifier::ReadOnly,
466           copyinReadonlyOperands, copyinOperands);
467     } else if (const auto *copyoutClause =
468                    std::get_if<Fortran::parser::AccClause::Copyout>(
469                        &clause.u)) {
470       genObjectListWithModifier<Fortran::parser::AccClause::Copyout>(
471           copyoutClause, converter,
472           Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands,
473           copyoutOperands);
474     } else if (const auto *createClause =
475                    std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
476       genObjectListWithModifier<Fortran::parser::AccClause::Create>(
477           createClause, converter,
478           Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
479           createOperands);
480     } else if (const auto *noCreateClause =
481                    std::get_if<Fortran::parser::AccClause::NoCreate>(
482                        &clause.u)) {
483       genObjectList(noCreateClause->v, converter, noCreateOperands);
484     } else if (const auto *presentClause =
485                    std::get_if<Fortran::parser::AccClause::Present>(
486                        &clause.u)) {
487       genObjectList(presentClause->v, converter, presentOperands);
488     } else if (const auto *deviceptrClause =
489                    std::get_if<Fortran::parser::AccClause::Deviceptr>(
490                        &clause.u)) {
491       genObjectList(deviceptrClause->v, converter, deviceptrOperands);
492     } else if (const auto *attachClause =
493                    std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
494       genObjectList(attachClause->v, converter, attachOperands);
495     }
496   }
497 
498   // Prepare the operand segement size attribute and the operands value range.
499   SmallVector<Value, 8> operands;
500   SmallVector<int32_t, 8> operandSegments;
501   addOperand(operands, operandSegments, ifCond);
502   addOperands(operands, operandSegments, copyOperands);
503   addOperands(operands, operandSegments, copyinOperands);
504   addOperands(operands, operandSegments, copyinReadonlyOperands);
505   addOperands(operands, operandSegments, copyoutOperands);
506   addOperands(operands, operandSegments, copyoutZeroOperands);
507   addOperands(operands, operandSegments, createOperands);
508   addOperands(operands, operandSegments, createZeroOperands);
509   addOperands(operands, operandSegments, noCreateOperands);
510   addOperands(operands, operandSegments, presentOperands);
511   addOperands(operands, operandSegments, deviceptrOperands);
512   addOperands(operands, operandSegments, attachOperands);
513 
514   createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>(
515       firOpBuilder, currentLocation, operands, operandSegments);
516 }
517 
518 static void
genACC(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenACCBlockConstruct & blockConstruct)519 genACC(Fortran::lower::AbstractConverter &converter,
520        Fortran::lower::pft::Evaluation &eval,
521        const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
522   const auto &beginBlockDirective =
523       std::get<Fortran::parser::AccBeginBlockDirective>(blockConstruct.t);
524   const auto &blockDirective =
525       std::get<Fortran::parser::AccBlockDirective>(beginBlockDirective.t);
526   const auto &accClauseList =
527       std::get<Fortran::parser::AccClauseList>(beginBlockDirective.t);
528 
529   if (blockDirective.v == llvm::acc::ACCD_parallel) {
530     genACCParallelOp(converter, accClauseList);
531   } else if (blockDirective.v == llvm::acc::ACCD_data) {
532     genACCDataOp(converter, accClauseList);
533   }
534 }
535 
536 static void
genACCEnterDataOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)537 genACCEnterDataOp(Fortran::lower::AbstractConverter &converter,
538                   const Fortran::parser::AccClauseList &accClauseList) {
539   mlir::Value ifCond, async, waitDevnum;
540   SmallVector<Value, 2> copyinOperands, createOperands, createZeroOperands,
541       attachOperands, waitOperands;
542 
543   // Async, wait and self clause have optional values but can be present with
544   // no value as well. When there is no value, the op has an attribute to
545   // represent the clause.
546   bool addAsyncAttr = false;
547   bool addWaitAttr = false;
548 
549   auto &firOpBuilder = converter.getFirOpBuilder();
550   auto currentLocation = converter.getCurrentLocation();
551 
552   // Lower clauses values mapped to operands.
553   // Keep track of each group of operands separatly as clauses can appear
554   // more than once.
555   for (const auto &clause : accClauseList.v) {
556     if (const auto *ifClause =
557             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
558       mlir::Value cond = fir::getBase(
559           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
560       ifCond = firOpBuilder.createConvert(currentLocation,
561                                           firOpBuilder.getI1Type(), cond);
562     } else if (const auto *asyncClause =
563                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
564       const auto &asyncClauseValue = asyncClause->v;
565       if (asyncClauseValue) { // async has a value.
566         async = fir::getBase(converter.genExprValue(
567             *Fortran::semantics::GetExpr(*asyncClauseValue)));
568       } else {
569         addAsyncAttr = true;
570       }
571     } else if (const auto *waitClause =
572                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
573       const auto &waitClauseValue = waitClause->v;
574       if (waitClauseValue) { // wait has a value.
575         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
576         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
577             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
578         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
579           mlir::Value v = fir::getBase(
580               converter.genExprValue(*Fortran::semantics::GetExpr(value)));
581           waitOperands.push_back(v);
582         }
583 
584         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
585             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
586         if (waitDevnumValue)
587           waitDevnum = fir::getBase(converter.genExprValue(
588               *Fortran::semantics::GetExpr(*waitDevnumValue)));
589       } else {
590         addWaitAttr = true;
591       }
592     } else if (const auto *copyinClause =
593                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
594       const Fortran::parser::AccObjectListWithModifier &listWithModifier =
595           copyinClause->v;
596       const Fortran::parser::AccObjectList &accObjectList =
597           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
598       genObjectList(accObjectList, converter, copyinOperands);
599     } else if (const auto *createClause =
600                    std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
601       genObjectListWithModifier<Fortran::parser::AccClause::Create>(
602           createClause, converter,
603           Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
604           createOperands);
605     } else if (const auto *attachClause =
606                    std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
607       genObjectList(attachClause->v, converter, attachOperands);
608     } else {
609       llvm::report_fatal_error(
610           "Unknown clause in ENTER DATA directive lowering");
611     }
612   }
613 
614   // Prepare the operand segement size attribute and the operands value range.
615   SmallVector<mlir::Value, 16> operands;
616   SmallVector<int32_t, 8> operandSegments;
617   addOperand(operands, operandSegments, ifCond);
618   addOperand(operands, operandSegments, async);
619   addOperand(operands, operandSegments, waitDevnum);
620   addOperands(operands, operandSegments, waitOperands);
621   addOperands(operands, operandSegments, copyinOperands);
622   addOperands(operands, operandSegments, createOperands);
623   addOperands(operands, operandSegments, createZeroOperands);
624   addOperands(operands, operandSegments, attachOperands);
625 
626   auto enterDataOp = createSimpleOp<mlir::acc::EnterDataOp>(
627       firOpBuilder, currentLocation, operands, operandSegments);
628 
629   if (addAsyncAttr)
630     enterDataOp.asyncAttr(firOpBuilder.getUnitAttr());
631   if (addWaitAttr)
632     enterDataOp.waitAttr(firOpBuilder.getUnitAttr());
633 }
634 
635 static void
genACCExitDataOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)636 genACCExitDataOp(Fortran::lower::AbstractConverter &converter,
637                  const Fortran::parser::AccClauseList &accClauseList) {
638   mlir::Value ifCond, async, waitDevnum;
639   SmallVector<Value, 2> copyoutOperands, deleteOperands, detachOperands,
640       waitOperands;
641 
642   // Async and wait clause have optional values but can be present with
643   // no value as well. When there is no value, the op has an attribute to
644   // represent the clause.
645   bool addAsyncAttr = false;
646   bool addWaitAttr = false;
647   bool addFinalizeAttr = false;
648 
649   auto &firOpBuilder = converter.getFirOpBuilder();
650   auto currentLocation = converter.getCurrentLocation();
651 
652   // Lower clauses values mapped to operands.
653   // Keep track of each group of operands separatly as clauses can appear
654   // more than once.
655   for (const auto &clause : accClauseList.v) {
656     if (const auto *ifClause =
657             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
658       Value cond = fir::getBase(
659           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
660       ifCond = firOpBuilder.createConvert(currentLocation,
661                                           firOpBuilder.getI1Type(), cond);
662     } else if (const auto *asyncClause =
663                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
664       const auto &asyncClauseValue = asyncClause->v;
665       if (asyncClauseValue) { // async has a value.
666         async = fir::getBase(converter.genExprValue(
667             *Fortran::semantics::GetExpr(*asyncClauseValue)));
668       } else {
669         addAsyncAttr = true;
670       }
671     } else if (const auto *waitClause =
672                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
673       const auto &waitClauseValue = waitClause->v;
674       if (waitClauseValue) { // wait has a value.
675         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
676         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
677             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
678         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
679           Value v = fir::getBase(
680               converter.genExprValue(*Fortran::semantics::GetExpr(value)));
681           waitOperands.push_back(v);
682         }
683 
684         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
685             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
686         if (waitDevnumValue)
687           waitDevnum = fir::getBase(converter.genExprValue(
688               *Fortran::semantics::GetExpr(*waitDevnumValue)));
689       } else {
690         addWaitAttr = true;
691       }
692     } else if (const auto *copyoutClause =
693                    std::get_if<Fortran::parser::AccClause::Copyout>(
694                        &clause.u)) {
695       const Fortran::parser::AccObjectListWithModifier &listWithModifier =
696           copyoutClause->v;
697       const Fortran::parser::AccObjectList &accObjectList =
698           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
699       genObjectList(accObjectList, converter, copyoutOperands);
700     } else if (const auto *deleteClause =
701                    std::get_if<Fortran::parser::AccClause::Delete>(&clause.u)) {
702       genObjectList(deleteClause->v, converter, deleteOperands);
703     } else if (const auto *detachClause =
704                    std::get_if<Fortran::parser::AccClause::Detach>(&clause.u)) {
705       genObjectList(detachClause->v, converter, detachOperands);
706     } else if (std::get_if<Fortran::parser::AccClause::Finalize>(&clause.u)) {
707       addFinalizeAttr = true;
708     }
709   }
710 
711   // Prepare the operand segement size attribute and the operands value range.
712   SmallVector<mlir::Value, 14> operands;
713   SmallVector<int32_t, 7> operandSegments;
714   addOperand(operands, operandSegments, ifCond);
715   addOperand(operands, operandSegments, async);
716   addOperand(operands, operandSegments, waitDevnum);
717   addOperands(operands, operandSegments, waitOperands);
718   addOperands(operands, operandSegments, copyoutOperands);
719   addOperands(operands, operandSegments, deleteOperands);
720   addOperands(operands, operandSegments, detachOperands);
721 
722   auto exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
723       firOpBuilder, currentLocation, operands, operandSegments);
724 
725   if (addAsyncAttr)
726     exitDataOp.asyncAttr(firOpBuilder.getUnitAttr());
727   if (addWaitAttr)
728     exitDataOp.waitAttr(firOpBuilder.getUnitAttr());
729   if (addFinalizeAttr)
730     exitDataOp.finalizeAttr(firOpBuilder.getUnitAttr());
731 }
732 
733 template <typename Op>
734 static void
genACCInitShutdownOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)735 genACCInitShutdownOp(Fortran::lower::AbstractConverter &converter,
736                      const Fortran::parser::AccClauseList &accClauseList) {
737   mlir::Value ifCond, deviceNum;
738   SmallVector<Value, 2> deviceTypeOperands;
739 
740   auto &firOpBuilder = converter.getFirOpBuilder();
741   auto currentLocation = converter.getCurrentLocation();
742 
743   // Lower clauses values mapped to operands.
744   // Keep track of each group of operands separatly as clauses can appear
745   // more than once.
746   for (const auto &clause : accClauseList.v) {
747     if (const auto *ifClause =
748             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
749       mlir::Value cond = fir::getBase(
750           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
751       ifCond = firOpBuilder.createConvert(currentLocation,
752                                           firOpBuilder.getI1Type(), cond);
753     } else if (const auto *deviceNumClause =
754                    std::get_if<Fortran::parser::AccClause::DeviceNum>(
755                        &clause.u)) {
756       deviceNum = fir::getBase(converter.genExprValue(
757           *Fortran::semantics::GetExpr(deviceNumClause->v)));
758     } else if (const auto *deviceTypeClause =
759                    std::get_if<Fortran::parser::AccClause::DeviceType>(
760                        &clause.u)) {
761 
762       const auto &deviceTypeValue = deviceTypeClause->v;
763       if (deviceTypeValue) {
764         for (const auto &scalarIntExpr : *deviceTypeValue) {
765           mlir::Value expr = fir::getBase(converter.genExprValue(
766               *Fortran::semantics::GetExpr(scalarIntExpr)));
767           deviceTypeOperands.push_back(expr);
768         }
769       } else {
770         // * was passed as value and will be represented as a -1 constant
771         // integer.
772         mlir::Value star = firOpBuilder.createIntegerConstant(
773             currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
774         deviceTypeOperands.push_back(star);
775       }
776     }
777   }
778 
779   // Prepare the operand segement size attribute and the operands value range.
780   SmallVector<mlir::Value, 6> operands;
781   SmallVector<int32_t, 3> operandSegments;
782   addOperands(operands, operandSegments, deviceTypeOperands);
783   addOperand(operands, operandSegments, deviceNum);
784   addOperand(operands, operandSegments, ifCond);
785 
786   createSimpleOp<Op>(firOpBuilder, currentLocation, operands, operandSegments);
787 }
788 
789 static void
genACCUpdateOp(Fortran::lower::AbstractConverter & converter,const Fortran::parser::AccClauseList & accClauseList)790 genACCUpdateOp(Fortran::lower::AbstractConverter &converter,
791                const Fortran::parser::AccClauseList &accClauseList) {
792   mlir::Value ifCond, async, waitDevnum;
793   SmallVector<Value, 2> hostOperands, deviceOperands, waitOperands,
794       deviceTypeOperands;
795 
796   // Async and wait clause have optional values but can be present with
797   // no value as well. When there is no value, the op has an attribute to
798   // represent the clause.
799   bool addAsyncAttr = false;
800   bool addWaitAttr = false;
801   bool addIfPresentAttr = false;
802 
803   auto &firOpBuilder = converter.getFirOpBuilder();
804   auto currentLocation = converter.getCurrentLocation();
805 
806   // Lower clauses values mapped to operands.
807   // Keep track of each group of operands separatly as clauses can appear
808   // more than once.
809   for (const auto &clause : accClauseList.v) {
810     if (const auto *ifClause =
811             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
812       mlir::Value cond = fir::getBase(
813           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
814       ifCond = firOpBuilder.createConvert(currentLocation,
815                                           firOpBuilder.getI1Type(), cond);
816     } else if (const auto *asyncClause =
817                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
818       const auto &asyncClauseValue = asyncClause->v;
819       if (asyncClauseValue) { // async has a value.
820         async = fir::getBase(converter.genExprValue(
821             *Fortran::semantics::GetExpr(*asyncClauseValue)));
822       } else {
823         addAsyncAttr = true;
824       }
825     } else if (const auto *waitClause =
826                    std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
827       const auto &waitClauseValue = waitClause->v;
828       if (waitClauseValue) { // wait has a value.
829         const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
830         const std::list<Fortran::parser::ScalarIntExpr> &waitList =
831             std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
832         for (const Fortran::parser::ScalarIntExpr &value : waitList) {
833           mlir::Value v = fir::getBase(
834               converter.genExprValue(*Fortran::semantics::GetExpr(value)));
835           waitOperands.push_back(v);
836         }
837 
838         const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
839             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
840         if (waitDevnumValue)
841           waitDevnum = fir::getBase(converter.genExprValue(
842               *Fortran::semantics::GetExpr(*waitDevnumValue)));
843       } else {
844         addWaitAttr = true;
845       }
846     } else if (const auto *deviceTypeClause =
847                    std::get_if<Fortran::parser::AccClause::DeviceType>(
848                        &clause.u)) {
849 
850       const auto &deviceTypeValue = deviceTypeClause->v;
851       if (deviceTypeValue) {
852         for (const auto &scalarIntExpr : *deviceTypeValue) {
853           mlir::Value expr = fir::getBase(converter.genExprValue(
854               *Fortran::semantics::GetExpr(scalarIntExpr)));
855           deviceTypeOperands.push_back(expr);
856         }
857       } else {
858         // * was passed as value and will be represented as a -1 constant
859         // integer.
860         mlir::Value star = firOpBuilder.createIntegerConstant(
861             currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
862         deviceTypeOperands.push_back(star);
863       }
864     } else if (const auto *hostClause =
865                    std::get_if<Fortran::parser::AccClause::Host>(&clause.u)) {
866       genObjectList(hostClause->v, converter, hostOperands);
867     } else if (const auto *deviceClause =
868                    std::get_if<Fortran::parser::AccClause::Device>(&clause.u)) {
869       genObjectList(deviceClause->v, converter, deviceOperands);
870     }
871   }
872 
873   // Prepare the operand segement size attribute and the operands value range.
874   SmallVector<mlir::Value, 14> operands;
875   SmallVector<int32_t, 7> operandSegments;
876   addOperand(operands, operandSegments, async);
877   addOperand(operands, operandSegments, waitDevnum);
878   addOperands(operands, operandSegments, waitOperands);
879   addOperands(operands, operandSegments, deviceTypeOperands);
880   addOperand(operands, operandSegments, ifCond);
881   addOperands(operands, operandSegments, hostOperands);
882   addOperands(operands, operandSegments, deviceOperands);
883 
884   auto updateOp = createSimpleOp<mlir::acc::UpdateOp>(
885       firOpBuilder, currentLocation, operands, operandSegments);
886 
887   if (addAsyncAttr)
888     updateOp.asyncAttr(firOpBuilder.getUnitAttr());
889   if (addWaitAttr)
890     updateOp.waitAttr(firOpBuilder.getUnitAttr());
891   if (addIfPresentAttr)
892     updateOp.ifPresentAttr(firOpBuilder.getUnitAttr());
893 }
894 
895 static void
genACC(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenACCStandaloneConstruct & standaloneConstruct)896 genACC(Fortran::lower::AbstractConverter &converter,
897        Fortran::lower::pft::Evaluation &eval,
898        const Fortran::parser::OpenACCStandaloneConstruct &standaloneConstruct) {
899   const auto &standaloneDirective =
900       std::get<Fortran::parser::AccStandaloneDirective>(standaloneConstruct.t);
901   const auto &accClauseList =
902       std::get<Fortran::parser::AccClauseList>(standaloneConstruct.t);
903 
904   if (standaloneDirective.v == llvm::acc::Directive::ACCD_enter_data) {
905     genACCEnterDataOp(converter, accClauseList);
906   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_exit_data) {
907     genACCExitDataOp(converter, accClauseList);
908   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_init) {
909     genACCInitShutdownOp<mlir::acc::InitOp>(converter, accClauseList);
910   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_shutdown) {
911     genACCInitShutdownOp<mlir::acc::ShutdownOp>(converter, accClauseList);
912   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_set) {
913     TODO("OpenACC set directive not lowered yet!");
914   } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_update) {
915     genACCUpdateOp(converter, accClauseList);
916   }
917 }
918 
genACC(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenACCWaitConstruct & waitConstruct)919 static void genACC(Fortran::lower::AbstractConverter &converter,
920                    Fortran::lower::pft::Evaluation &eval,
921                    const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
922 
923   const auto &waitArgument =
924       std::get<std::optional<Fortran::parser::AccWaitArgument>>(
925           waitConstruct.t);
926   const auto &accClauseList =
927       std::get<Fortran::parser::AccClauseList>(waitConstruct.t);
928 
929   mlir::Value ifCond, asyncOperand, waitDevnum, async;
930   SmallVector<mlir::Value, 2> waitOperands;
931 
932   // Async clause have optional values but can be present with
933   // no value as well. When there is no value, the op has an attribute to
934   // represent the clause.
935   bool addAsyncAttr = false;
936 
937   auto &firOpBuilder = converter.getFirOpBuilder();
938   auto currentLocation = converter.getCurrentLocation();
939 
940   if (waitArgument) { // wait has a value.
941     const Fortran::parser::AccWaitArgument &waitArg = *waitArgument;
942     const std::list<Fortran::parser::ScalarIntExpr> &waitList =
943         std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
944     for (const Fortran::parser::ScalarIntExpr &value : waitList) {
945       mlir::Value v = fir::getBase(
946           converter.genExprValue(*Fortran::semantics::GetExpr(value)));
947       waitOperands.push_back(v);
948     }
949 
950     const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
951         std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
952     if (waitDevnumValue)
953       waitDevnum = fir::getBase(converter.genExprValue(
954           *Fortran::semantics::GetExpr(*waitDevnumValue)));
955   }
956 
957   // Lower clauses values mapped to operands.
958   // Keep track of each group of operands separatly as clauses can appear
959   // more than once.
960   for (const auto &clause : accClauseList.v) {
961     if (const auto *ifClause =
962             std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
963       mlir::Value cond = fir::getBase(
964           converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
965       ifCond = firOpBuilder.createConvert(currentLocation,
966                                           firOpBuilder.getI1Type(), cond);
967     } else if (const auto *asyncClause =
968                    std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
969       const auto &asyncClauseValue = asyncClause->v;
970       if (asyncClauseValue) { // async has a value.
971         async = fir::getBase(converter.genExprValue(
972             *Fortran::semantics::GetExpr(*asyncClauseValue)));
973       } else {
974         addAsyncAttr = true;
975       }
976     }
977   }
978 
979   // Prepare the operand segement size attribute and the operands value range.
980   SmallVector<mlir::Value, 8> operands;
981   SmallVector<int32_t, 4> operandSegments;
982   addOperands(operands, operandSegments, waitOperands);
983   addOperand(operands, operandSegments, async);
984   addOperand(operands, operandSegments, waitDevnum);
985   addOperand(operands, operandSegments, ifCond);
986 
987   auto waitOp = createSimpleOp<mlir::acc::WaitOp>(firOpBuilder, currentLocation,
988                                                   operands, operandSegments);
989 
990   if (addAsyncAttr)
991     waitOp.asyncAttr(firOpBuilder.getUnitAttr());
992 }
993 
genOpenACCConstruct(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenACCConstruct & accConstruct)994 void Fortran::lower::genOpenACCConstruct(
995     Fortran::lower::AbstractConverter &converter,
996     Fortran::lower::pft::Evaluation &eval,
997     const Fortran::parser::OpenACCConstruct &accConstruct) {
998 
999   std::visit(
1000       common::visitors{
1001           [&](const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
1002             genACC(converter, eval, blockConstruct);
1003           },
1004           [&](const Fortran::parser::OpenACCCombinedConstruct
1005                   &combinedConstruct) {
1006             TODO("OpenACC Combined construct not lowered yet!");
1007           },
1008           [&](const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
1009             genACC(converter, eval, loopConstruct);
1010           },
1011           [&](const Fortran::parser::OpenACCStandaloneConstruct
1012                   &standaloneConstruct) {
1013             genACC(converter, eval, standaloneConstruct);
1014           },
1015           [&](const Fortran::parser::OpenACCRoutineConstruct
1016                   &routineConstruct) {
1017             TODO("OpenACC Routine construct not lowered yet!");
1018           },
1019           [&](const Fortran::parser::OpenACCCacheConstruct &cacheConstruct) {
1020             TODO("OpenACC Cache construct not lowered yet!");
1021           },
1022           [&](const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
1023             genACC(converter, eval, waitConstruct);
1024           },
1025           [&](const Fortran::parser::OpenACCAtomicConstruct &atomicConstruct) {
1026             TODO("OpenACC Atomic construct not lowered yet!");
1027           },
1028       },
1029       accConstruct.u);
1030 }
1031