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