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