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/Parser/parse-tree.h" 20 #include "flang/Semantics/tools.h" 21 #include "mlir/Dialect/OpenACC/OpenACC.h" 22 #include "llvm/Frontend/OpenACC/ACC.h.inc" 23 24 #define TODO() llvm_unreachable("not yet implemented") 25 26 static const Fortran::parser::Name * 27 getDesignatorNameIfDataRef(const Fortran::parser::Designator &designator) { 28 const auto *dataRef{std::get_if<Fortran::parser::DataRef>(&designator.u)}; 29 return dataRef ? std::get_if<Fortran::parser::Name>(&dataRef->u) : nullptr; 30 } 31 32 static void genObjectList(const Fortran::parser::AccObjectList &objectList, 33 Fortran::lower::AbstractConverter &converter, 34 SmallVectorImpl<Value> &operands) { 35 for (const auto &accObject : objectList.v) { 36 std::visit( 37 Fortran::common::visitors{ 38 [&](const Fortran::parser::Designator &designator) { 39 if (const auto *name = getDesignatorNameIfDataRef(designator)) { 40 const auto variable = converter.getSymbolAddress(*name->symbol); 41 operands.push_back(variable); 42 } 43 }, 44 [&](const Fortran::parser::Name &name) { 45 const auto variable = converter.getSymbolAddress(*name.symbol); 46 operands.push_back(variable); 47 }}, 48 accObject.u); 49 } 50 } 51 52 template <typename Clause> 53 static void 54 genObjectListWithModifier(const Clause *x, 55 Fortran::lower::AbstractConverter &converter, 56 Fortran::parser::AccDataModifier::Modifier mod, 57 SmallVectorImpl<Value> &operandsWithModifier, 58 SmallVectorImpl<Value> &operands) { 59 const Fortran::parser::AccObjectListWithModifier &listWithModifier = x->v; 60 const Fortran::parser::AccObjectList &accObjectList = 61 std::get<Fortran::parser::AccObjectList>(listWithModifier.t); 62 const auto &modifier = 63 std::get<std::optional<Fortran::parser::AccDataModifier>>( 64 listWithModifier.t); 65 if (modifier && (*modifier).v == mod) { 66 genObjectList(accObjectList, converter, operandsWithModifier); 67 } else { 68 genObjectList(accObjectList, converter, operands); 69 } 70 } 71 72 static void addOperands(SmallVectorImpl<Value> &operands, 73 SmallVectorImpl<int32_t> &operandSegments, 74 const SmallVectorImpl<Value> &clauseOperands) { 75 operands.append(clauseOperands.begin(), clauseOperands.end()); 76 operandSegments.push_back(clauseOperands.size()); 77 } 78 79 static void addOperand(SmallVectorImpl<Value> &operands, 80 SmallVectorImpl<int32_t> &operandSegments, 81 const Value &clauseOperand) { 82 if (clauseOperand) { 83 operands.push_back(clauseOperand); 84 operandSegments.push_back(1); 85 } else { 86 operandSegments.push_back(0); 87 } 88 } 89 90 template <typename Op, typename Terminator> 91 static Op createRegionOp(Fortran::lower::FirOpBuilder &builder, 92 mlir::Location loc, 93 const SmallVectorImpl<Value> &operands, 94 const SmallVectorImpl<int32_t> &operandSegments) { 95 llvm::ArrayRef<mlir::Type> argTy; 96 Op op = builder.create<Op>(loc, argTy, operands); 97 builder.createBlock(&op.getRegion()); 98 auto &block = op.getRegion().back(); 99 builder.setInsertionPointToStart(&block); 100 builder.create<Terminator>(loc); 101 102 op.setAttr(Op::getOperandSegmentSizeAttr(), 103 builder.getI32VectorAttr(operandSegments)); 104 105 // Place the insertion point to the start of the first block. 106 builder.setInsertionPointToStart(&block); 107 108 return op; 109 } 110 111 static void genACC(Fortran::lower::AbstractConverter &converter, 112 Fortran::lower::pft::Evaluation &eval, 113 const Fortran::parser::OpenACCLoopConstruct &loopConstruct) { 114 115 const auto &beginLoopDirective = 116 std::get<Fortran::parser::AccBeginLoopDirective>(loopConstruct.t); 117 const auto &loopDirective = 118 std::get<Fortran::parser::AccLoopDirective>(beginLoopDirective.t); 119 120 if (loopDirective.v == llvm::acc::ACCD_loop) { 121 auto &firOpBuilder = converter.getFirOpBuilder(); 122 auto currentLocation = converter.getCurrentLocation(); 123 124 // Add attribute extracted from clauses. 125 const auto &accClauseList = 126 std::get<Fortran::parser::AccClauseList>(beginLoopDirective.t); 127 128 mlir::Value workerNum; 129 mlir::Value vectorLength; 130 mlir::Value gangNum; 131 mlir::Value gangStatic; 132 SmallVector<Value, 2> tileOperands, privateOperands, reductionOperands; 133 std::int64_t executionMapping = mlir::acc::OpenACCExecMapping::NONE; 134 135 // Lower clauses values mapped to operands. 136 for (const auto &clause : accClauseList.v) { 137 if (const auto *gangClause = 138 std::get_if<Fortran::parser::AccClause::Gang>(&clause.u)) { 139 if (gangClause->v) { 140 const Fortran::parser::AccGangArgument &x = *gangClause->v; 141 if (const auto &gangNumValue = 142 std::get<std::optional<Fortran::parser::ScalarIntExpr>>( 143 x.t)) { 144 gangNum = fir::getBase(converter.genExprValue( 145 *Fortran::semantics::GetExpr(gangNumValue.value()))); 146 } 147 if (const auto &gangStaticValue = 148 std::get<std::optional<Fortran::parser::AccSizeExpr>>(x.t)) { 149 const auto &expr = 150 std::get<std::optional<Fortran::parser::ScalarIntExpr>>( 151 gangStaticValue.value().t); 152 if (expr) { 153 gangStatic = fir::getBase( 154 converter.genExprValue(*Fortran::semantics::GetExpr(*expr))); 155 } else { 156 // * was passed as value and will be represented as a -1 constant 157 // integer. 158 gangStatic = firOpBuilder.createIntegerConstant( 159 currentLocation, firOpBuilder.getIntegerType(32), 160 /* STAR */ -1); 161 } 162 } 163 } 164 executionMapping |= mlir::acc::OpenACCExecMapping::GANG; 165 } else if (const auto *workerClause = 166 std::get_if<Fortran::parser::AccClause::Worker>( 167 &clause.u)) { 168 if (workerClause->v) { 169 workerNum = fir::getBase(converter.genExprValue( 170 *Fortran::semantics::GetExpr(*workerClause->v))); 171 } 172 executionMapping |= mlir::acc::OpenACCExecMapping::WORKER; 173 } else if (const auto *vectorClause = 174 std::get_if<Fortran::parser::AccClause::Vector>( 175 &clause.u)) { 176 if (vectorClause->v) { 177 vectorLength = fir::getBase(converter.genExprValue( 178 *Fortran::semantics::GetExpr(*vectorClause->v))); 179 } 180 executionMapping |= mlir::acc::OpenACCExecMapping::VECTOR; 181 } else if (const auto *tileClause = 182 std::get_if<Fortran::parser::AccClause::Tile>(&clause.u)) { 183 const Fortran::parser::AccTileExprList &accTileExprList = tileClause->v; 184 for (const auto &accTileExpr : accTileExprList.v) { 185 const auto &expr = 186 std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>( 187 accTileExpr.t); 188 if (expr) { 189 tileOperands.push_back(fir::getBase( 190 converter.genExprValue(*Fortran::semantics::GetExpr(*expr)))); 191 } else { 192 // * was passed as value and will be represented as a -1 constant 193 // integer. 194 mlir::Value tileStar = firOpBuilder.createIntegerConstant( 195 currentLocation, firOpBuilder.getIntegerType(32), 196 /* STAR */ -1); 197 tileOperands.push_back(tileStar); 198 } 199 } 200 } else if (const auto *privateClause = 201 std::get_if<Fortran::parser::AccClause::Private>( 202 &clause.u)) { 203 genObjectList(privateClause->v, converter, privateOperands); 204 } 205 // Reduction clause is left out for the moment as the clause will probably 206 // end up having its own operation. 207 } 208 209 // Prepare the operand segement size attribute and the operands value range. 210 SmallVector<Value, 8> operands; 211 SmallVector<int32_t, 8> operandSegments; 212 addOperand(operands, operandSegments, gangNum); 213 addOperand(operands, operandSegments, gangStatic); 214 addOperand(operands, operandSegments, workerNum); 215 addOperand(operands, operandSegments, vectorLength); 216 addOperands(operands, operandSegments, tileOperands); 217 addOperands(operands, operandSegments, privateOperands); 218 addOperands(operands, operandSegments, reductionOperands); 219 220 auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>( 221 firOpBuilder, currentLocation, operands, operandSegments); 222 223 loopOp.setAttr(mlir::acc::LoopOp::getExecutionMappingAttrName(), 224 firOpBuilder.getI64IntegerAttr(executionMapping)); 225 226 // Lower clauses mapped to attributes 227 for (const auto &clause : accClauseList.v) { 228 if (const auto *collapseClause = 229 std::get_if<Fortran::parser::AccClause::Collapse>(&clause.u)) { 230 const auto *expr = Fortran::semantics::GetExpr(collapseClause->v); 231 const auto collapseValue = Fortran::evaluate::ToInt64(*expr); 232 if (collapseValue) { 233 loopOp.setAttr(mlir::acc::LoopOp::getCollapseAttrName(), 234 firOpBuilder.getI64IntegerAttr(*collapseValue)); 235 } 236 } else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) { 237 loopOp.setAttr(mlir::acc::LoopOp::getSeqAttrName(), 238 firOpBuilder.getUnitAttr()); 239 } else if (std::get_if<Fortran::parser::AccClause::Independent>( 240 &clause.u)) { 241 loopOp.setAttr(mlir::acc::LoopOp::getIndependentAttrName(), 242 firOpBuilder.getUnitAttr()); 243 } else if (std::get_if<Fortran::parser::AccClause::Auto>(&clause.u)) { 244 loopOp.setAttr(mlir::acc::LoopOp::getAutoAttrName(), 245 firOpBuilder.getUnitAttr()); 246 } 247 } 248 } 249 } 250 251 static void 252 genACCParallelOp(Fortran::lower::AbstractConverter &converter, 253 const Fortran::parser::AccClauseList &accClauseList) { 254 mlir::Value async; 255 mlir::Value numGangs; 256 mlir::Value numWorkers; 257 mlir::Value vectorLength; 258 mlir::Value ifCond; 259 mlir::Value selfCond; 260 SmallVector<Value, 2> waitOperands, reductionOperands, copyOperands, 261 copyinOperands, copyinReadonlyOperands, copyoutOperands, 262 copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands, 263 presentOperands, devicePtrOperands, attachOperands, privateOperands, 264 firstprivateOperands; 265 266 // Async, wait and self clause have optional values but can be present with 267 // no value as well. When there is no value, the op has an attribute to 268 // represent the clause. 269 bool addAsyncAttr = false; 270 bool addWaitAttr = false; 271 bool addSelfAttr = false; 272 273 auto &firOpBuilder = converter.getFirOpBuilder(); 274 auto currentLocation = converter.getCurrentLocation(); 275 276 // Lower clauses values mapped to operands. 277 // Keep track of each group of operands separatly as clauses can appear 278 // more than once. 279 for (const auto &clause : accClauseList.v) { 280 if (const auto *asyncClause = 281 std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) { 282 const auto &asyncClauseValue = asyncClause->v; 283 if (asyncClauseValue) { // async has a value. 284 async = fir::getBase(converter.genExprValue( 285 *Fortran::semantics::GetExpr(*asyncClauseValue))); 286 } else { 287 addAsyncAttr = true; 288 } 289 } else if (const auto *waitClause = 290 std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) { 291 const auto &waitClauseValue = waitClause->v; 292 if (waitClauseValue) { // wait has a value. 293 const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue; 294 const std::list<Fortran::parser::ScalarIntExpr> &waitList = 295 std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t); 296 for (const Fortran::parser::ScalarIntExpr &value : waitList) { 297 Value v = fir::getBase( 298 converter.genExprValue(*Fortran::semantics::GetExpr(value))); 299 waitOperands.push_back(v); 300 } 301 } else { 302 addWaitAttr = true; 303 } 304 } else if (const auto *numGangsClause = 305 std::get_if<Fortran::parser::AccClause::NumGangs>( 306 &clause.u)) { 307 numGangs = fir::getBase(converter.genExprValue( 308 *Fortran::semantics::GetExpr(numGangsClause->v))); 309 } else if (const auto *numWorkersClause = 310 std::get_if<Fortran::parser::AccClause::NumWorkers>( 311 &clause.u)) { 312 numWorkers = fir::getBase(converter.genExprValue( 313 *Fortran::semantics::GetExpr(numWorkersClause->v))); 314 } else if (const auto *vectorLengthClause = 315 std::get_if<Fortran::parser::AccClause::VectorLength>( 316 &clause.u)) { 317 vectorLength = fir::getBase(converter.genExprValue( 318 *Fortran::semantics::GetExpr(vectorLengthClause->v))); 319 } else if (const auto *ifClause = 320 std::get_if<Fortran::parser::AccClause::If>(&clause.u)) { 321 Value cond = fir::getBase( 322 converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v))); 323 ifCond = firOpBuilder.createConvert(currentLocation, 324 firOpBuilder.getI1Type(), cond); 325 } else if (const auto *selfClause = 326 std::get_if<Fortran::parser::AccClause::Self>(&clause.u)) { 327 if (selfClause->v) { 328 Value cond = fir::getBase(converter.genExprValue( 329 *Fortran::semantics::GetExpr(*(selfClause->v)))); 330 selfCond = firOpBuilder.createConvert(currentLocation, 331 firOpBuilder.getI1Type(), cond); 332 } else { 333 addSelfAttr = true; 334 } 335 } else if (const auto *copyClause = 336 std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) { 337 genObjectList(copyClause->v, converter, copyOperands); 338 } else if (const auto *copyinClause = 339 std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) { 340 genObjectListWithModifier<Fortran::parser::AccClause::Copyin>( 341 copyinClause, converter, 342 Fortran::parser::AccDataModifier::Modifier::ReadOnly, 343 copyinReadonlyOperands, copyinOperands); 344 } else if (const auto *copyoutClause = 345 std::get_if<Fortran::parser::AccClause::Copyout>( 346 &clause.u)) { 347 genObjectListWithModifier<Fortran::parser::AccClause::Copyout>( 348 copyoutClause, converter, 349 Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands, 350 copyoutOperands); 351 } else if (const auto *createClause = 352 std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) { 353 genObjectListWithModifier<Fortran::parser::AccClause::Create>( 354 createClause, converter, 355 Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands, 356 createOperands); 357 } else if (const auto *noCreateClause = 358 std::get_if<Fortran::parser::AccClause::NoCreate>( 359 &clause.u)) { 360 genObjectList(noCreateClause->v, converter, noCreateOperands); 361 } else if (const auto *presentClause = 362 std::get_if<Fortran::parser::AccClause::Present>( 363 &clause.u)) { 364 genObjectList(presentClause->v, converter, presentOperands); 365 } else if (const auto *devicePtrClause = 366 std::get_if<Fortran::parser::AccClause::Deviceptr>( 367 &clause.u)) { 368 genObjectList(devicePtrClause->v, converter, devicePtrOperands); 369 } else if (const auto *attachClause = 370 std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) { 371 genObjectList(attachClause->v, converter, attachOperands); 372 } else if (const auto *privateClause = 373 std::get_if<Fortran::parser::AccClause::Private>( 374 &clause.u)) { 375 genObjectList(privateClause->v, converter, privateOperands); 376 } else if (const auto *firstprivateClause = 377 std::get_if<Fortran::parser::AccClause::Firstprivate>( 378 &clause.u)) { 379 genObjectList(firstprivateClause->v, converter, firstprivateOperands); 380 } 381 } 382 383 // Prepare the operand segement size attribute and the operands value range. 384 SmallVector<Value, 8> operands; 385 SmallVector<int32_t, 8> operandSegments; 386 addOperand(operands, operandSegments, async); 387 addOperands(operands, operandSegments, waitOperands); 388 addOperand(operands, operandSegments, numGangs); 389 addOperand(operands, operandSegments, numWorkers); 390 addOperand(operands, operandSegments, vectorLength); 391 addOperand(operands, operandSegments, ifCond); 392 addOperand(operands, operandSegments, selfCond); 393 addOperands(operands, operandSegments, reductionOperands); 394 addOperands(operands, operandSegments, copyOperands); 395 addOperands(operands, operandSegments, copyinOperands); 396 addOperands(operands, operandSegments, copyinReadonlyOperands); 397 addOperands(operands, operandSegments, copyoutOperands); 398 addOperands(operands, operandSegments, copyoutZeroOperands); 399 addOperands(operands, operandSegments, createOperands); 400 addOperands(operands, operandSegments, createZeroOperands); 401 addOperands(operands, operandSegments, noCreateOperands); 402 addOperands(operands, operandSegments, presentOperands); 403 addOperands(operands, operandSegments, devicePtrOperands); 404 addOperands(operands, operandSegments, attachOperands); 405 addOperands(operands, operandSegments, privateOperands); 406 addOperands(operands, operandSegments, firstprivateOperands); 407 408 auto parallelOp = createRegionOp<mlir::acc::ParallelOp, mlir::acc::YieldOp>( 409 firOpBuilder, currentLocation, operands, operandSegments); 410 411 if (addAsyncAttr) 412 parallelOp.setAttr(mlir::acc::ParallelOp::getAsyncAttrName(), 413 firOpBuilder.getUnitAttr()); 414 if (addWaitAttr) 415 parallelOp.setAttr(mlir::acc::ParallelOp::getWaitAttrName(), 416 firOpBuilder.getUnitAttr()); 417 if (addSelfAttr) 418 parallelOp.setAttr(mlir::acc::ParallelOp::getSelfAttrName(), 419 firOpBuilder.getUnitAttr()); 420 } 421 422 static void genACCDataOp(Fortran::lower::AbstractConverter &converter, 423 const Fortran::parser::AccClauseList &accClauseList) { 424 mlir::Value ifCond; 425 SmallVector<Value, 2> copyOperands, copyinOperands, copyinReadonlyOperands, 426 copyoutOperands, copyoutZeroOperands, createOperands, createZeroOperands, 427 noCreateOperands, presentOperands, deviceptrOperands, attachOperands; 428 429 auto &firOpBuilder = converter.getFirOpBuilder(); 430 auto currentLocation = converter.getCurrentLocation(); 431 432 // Lower clauses values mapped to operands. 433 // Keep track of each group of operands separatly as clauses can appear 434 // more than once. 435 for (const auto &clause : accClauseList.v) { 436 if (const auto *ifClause = 437 std::get_if<Fortran::parser::AccClause::If>(&clause.u)) { 438 Value cond = fir::getBase( 439 converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v))); 440 ifCond = firOpBuilder.createConvert(currentLocation, 441 firOpBuilder.getI1Type(), cond); 442 } else if (const auto *copyClause = 443 std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) { 444 genObjectList(copyClause->v, converter, copyOperands); 445 } else if (const auto *copyinClause = 446 std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) { 447 genObjectListWithModifier<Fortran::parser::AccClause::Copyin>( 448 copyinClause, converter, 449 Fortran::parser::AccDataModifier::Modifier::ReadOnly, 450 copyinReadonlyOperands, copyinOperands); 451 } else if (const auto *copyoutClause = 452 std::get_if<Fortran::parser::AccClause::Copyout>( 453 &clause.u)) { 454 genObjectListWithModifier<Fortran::parser::AccClause::Copyout>( 455 copyoutClause, converter, 456 Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands, 457 copyoutOperands); 458 } else if (const auto *createClause = 459 std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) { 460 genObjectListWithModifier<Fortran::parser::AccClause::Create>( 461 createClause, converter, 462 Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands, 463 createOperands); 464 } else if (const auto *noCreateClause = 465 std::get_if<Fortran::parser::AccClause::NoCreate>( 466 &clause.u)) { 467 genObjectList(noCreateClause->v, converter, noCreateOperands); 468 } else if (const auto *presentClause = 469 std::get_if<Fortran::parser::AccClause::Present>( 470 &clause.u)) { 471 genObjectList(presentClause->v, converter, presentOperands); 472 } else if (const auto *deviceptrClause = 473 std::get_if<Fortran::parser::AccClause::Deviceptr>( 474 &clause.u)) { 475 genObjectList(deviceptrClause->v, converter, deviceptrOperands); 476 } else if (const auto *attachClause = 477 std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) { 478 genObjectList(attachClause->v, converter, attachOperands); 479 } 480 } 481 482 // Prepare the operand segement size attribute and the operands value range. 483 SmallVector<Value, 8> operands; 484 SmallVector<int32_t, 8> operandSegments; 485 addOperand(operands, operandSegments, ifCond); 486 addOperands(operands, operandSegments, copyOperands); 487 addOperands(operands, operandSegments, copyinOperands); 488 addOperands(operands, operandSegments, copyinReadonlyOperands); 489 addOperands(operands, operandSegments, copyoutOperands); 490 addOperands(operands, operandSegments, copyoutZeroOperands); 491 addOperands(operands, operandSegments, createOperands); 492 addOperands(operands, operandSegments, createZeroOperands); 493 addOperands(operands, operandSegments, noCreateOperands); 494 addOperands(operands, operandSegments, presentOperands); 495 addOperands(operands, operandSegments, deviceptrOperands); 496 addOperands(operands, operandSegments, attachOperands); 497 498 createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>( 499 firOpBuilder, currentLocation, operands, operandSegments); 500 } 501 502 static void 503 genACC(Fortran::lower::AbstractConverter &converter, 504 Fortran::lower::pft::Evaluation &eval, 505 const Fortran::parser::OpenACCBlockConstruct &blockConstruct) { 506 const auto &beginBlockDirective = 507 std::get<Fortran::parser::AccBeginBlockDirective>(blockConstruct.t); 508 const auto &blockDirective = 509 std::get<Fortran::parser::AccBlockDirective>(beginBlockDirective.t); 510 const auto &accClauseList = 511 std::get<Fortran::parser::AccClauseList>(beginBlockDirective.t); 512 513 if (blockDirective.v == llvm::acc::ACCD_parallel) { 514 genACCParallelOp(converter, accClauseList); 515 } else if (blockDirective.v == llvm::acc::ACCD_data) { 516 genACCDataOp(converter, accClauseList); 517 } 518 } 519 520 void Fortran::lower::genOpenACCConstruct( 521 Fortran::lower::AbstractConverter &converter, 522 Fortran::lower::pft::Evaluation &eval, 523 const Fortran::parser::OpenACCConstruct &accConstruct) { 524 525 std::visit( 526 common::visitors{ 527 [&](const Fortran::parser::OpenACCBlockConstruct &blockConstruct) { 528 genACC(converter, eval, blockConstruct); 529 }, 530 [&](const Fortran::parser::OpenACCCombinedConstruct 531 &combinedConstruct) { TODO(); }, 532 [&](const Fortran::parser::OpenACCLoopConstruct &loopConstruct) { 533 genACC(converter, eval, loopConstruct); 534 }, 535 [&](const Fortran::parser::OpenACCStandaloneConstruct 536 &standaloneConstruct) { TODO(); }, 537 [&](const Fortran::parser::OpenACCRoutineConstruct 538 &routineConstruct) { TODO(); }, 539 [&](const Fortran::parser::OpenACCCacheConstruct &cacheConstruct) { 540 TODO(); 541 }, 542 [&](const Fortran::parser::OpenACCWaitConstruct &waitConstruct) { 543 TODO(); 544 }, 545 [&](const Fortran::parser::OpenACCAtomicConstruct &atomicConstruct) { 546 TODO(); 547 }, 548 }, 549 accConstruct.u); 550 } 551