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