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