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 * 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 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> 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 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 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 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 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 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 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 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 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 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 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 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 534 genACCParallelOp(Fortran::lower::AbstractConverter &converter, 535 const Fortran::parser::AccClauseList &accClauseList) { 536 createParallelOp(converter, accClauseList); 537 } 538 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 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 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 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 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 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 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 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 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 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 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 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