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