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