1 //===- OpenACC.cpp - OpenACC MLIR Operations ------------------------------===// 2 // 3 // Part of the MLIR 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 #include "mlir/Dialect/OpenACC/OpenACC.h" 10 #include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc" 11 #include "mlir/IR/Builders.h" 12 #include "mlir/IR/OpImplementation.h" 13 #include "mlir/IR/StandardTypes.h" 14 15 using namespace mlir; 16 using namespace acc; 17 18 //===----------------------------------------------------------------------===// 19 // OpenACC operations 20 //===----------------------------------------------------------------------===// 21 22 void OpenACCDialect::initialize() { 23 addOperations< 24 #define GET_OP_LIST 25 #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc" 26 >(); 27 } 28 29 template <typename StructureOp> 30 static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, 31 unsigned nRegions = 1) { 32 33 SmallVector<Region *, 2> regions; 34 for (unsigned i = 0; i < nRegions; ++i) 35 regions.push_back(state.addRegion()); 36 37 for (Region *region : regions) { 38 if (parser.parseRegion(*region, /*arguments=*/{}, /*argTypes=*/{})) 39 return failure(); 40 } 41 42 return success(); 43 } 44 45 static ParseResult 46 parseOperandList(OpAsmParser &parser, StringRef keyword, 47 SmallVectorImpl<OpAsmParser::OperandType> &args, 48 SmallVectorImpl<Type> &argTypes, OperationState &result) { 49 if (failed(parser.parseOptionalKeyword(keyword))) 50 return success(); 51 52 if (failed(parser.parseLParen())) 53 return failure(); 54 55 // Exit early if the list is empty. 56 if (succeeded(parser.parseOptionalRParen())) 57 return success(); 58 59 do { 60 OpAsmParser::OperandType arg; 61 Type type; 62 63 if (parser.parseRegionArgument(arg) || parser.parseColonType(type)) 64 return failure(); 65 66 args.push_back(arg); 67 argTypes.push_back(type); 68 } while (succeeded(parser.parseOptionalComma())); 69 70 if (failed(parser.parseRParen())) 71 return failure(); 72 73 return parser.resolveOperands(args, argTypes, parser.getCurrentLocation(), 74 result.operands); 75 } 76 77 static void printOperandList(Operation::operand_range operands, 78 StringRef listName, OpAsmPrinter &printer) { 79 80 if (operands.size() > 0) { 81 printer << " " << listName << "("; 82 llvm::interleaveComma(operands, printer, [&](Value op) { 83 printer << op << ": " << op.getType(); 84 }); 85 printer << ")"; 86 } 87 } 88 89 static ParseResult parseOptionalOperand(OpAsmParser &parser, StringRef keyword, 90 OpAsmParser::OperandType &operand, 91 Type type, bool &hasOptional, 92 OperationState &result) { 93 hasOptional = false; 94 if (succeeded(parser.parseOptionalKeyword(keyword))) { 95 hasOptional = true; 96 if (parser.parseLParen() || parser.parseOperand(operand) || 97 parser.resolveOperand(operand, type, result.operands) || 98 parser.parseRParen()) 99 return failure(); 100 } 101 return success(); 102 } 103 104 static OptionalParseResult parseOptionalOperandAndType(OpAsmParser &parser, 105 StringRef keyword, 106 OperationState &result) { 107 OpAsmParser::OperandType operand; 108 Type type; 109 if (succeeded(parser.parseOptionalKeyword(keyword))) { 110 if (parser.parseLParen() || parser.parseOperand(operand) || 111 parser.parseColonType(type) || 112 parser.resolveOperand(operand, type, result.operands) || 113 parser.parseRParen()) 114 return failure(); 115 return success(); 116 } 117 return llvm::None; 118 } 119 120 //===----------------------------------------------------------------------===// 121 // ParallelOp 122 //===----------------------------------------------------------------------===// 123 124 /// Parse acc.parallel operation 125 /// operation := `acc.parallel` `async` `(` index `)`? 126 /// `wait` `(` index-list `)`? 127 /// `num_gangs` `(` value `)`? 128 /// `num_workers` `(` value `)`? 129 /// `vector_length` `(` value `)`? 130 /// `if` `(` value `)`? 131 /// `self` `(` value `)`? 132 /// `reduction` `(` value-list `)`? 133 /// `copy` `(` value-list `)`? 134 /// `copyin` `(` value-list `)`? 135 /// `copyin_readonly` `(` value-list `)`? 136 /// `copyout` `(` value-list `)`? 137 /// `copyout_zero` `(` value-list `)`? 138 /// `create` `(` value-list `)`? 139 /// `create_zero` `(` value-list `)`? 140 /// `no_create` `(` value-list `)`? 141 /// `present` `(` value-list `)`? 142 /// `deviceptr` `(` value-list `)`? 143 /// `attach` `(` value-list `)`? 144 /// `private` `(` value-list `)`? 145 /// `firstprivate` `(` value-list `)`? 146 /// region attr-dict? 147 static ParseResult parseParallelOp(OpAsmParser &parser, 148 OperationState &result) { 149 Builder &builder = parser.getBuilder(); 150 SmallVector<OpAsmParser::OperandType, 8> privateOperands, 151 firstprivateOperands, copyOperands, copyinOperands, 152 copyinReadonlyOperands, copyoutOperands, copyoutZeroOperands, 153 createOperands, createZeroOperands, noCreateOperands, presentOperands, 154 devicePtrOperands, attachOperands, waitOperands, reductionOperands; 155 SmallVector<Type, 8> waitOperandTypes, reductionOperandTypes, 156 copyOperandTypes, copyinOperandTypes, copyinReadonlyOperandTypes, 157 copyoutOperandTypes, copyoutZeroOperandTypes, createOperandTypes, 158 createZeroOperandTypes, noCreateOperandTypes, presentOperandTypes, 159 deviceptrOperandTypes, attachOperandTypes, privateOperandTypes, 160 firstprivateOperandTypes; 161 162 SmallVector<Type, 8> operandTypes; 163 OpAsmParser::OperandType ifCond, selfCond; 164 bool hasIfCond = false, hasSelfCond = false; 165 OptionalParseResult async, numGangs, numWorkers, vectorLength; 166 Type i1Type = builder.getI1Type(); 167 168 // async()? 169 async = parseOptionalOperandAndType(parser, ParallelOp::getAsyncKeyword(), 170 result); 171 if (async.hasValue() && failed(*async)) 172 return failure(); 173 174 // wait()? 175 if (failed(parseOperandList(parser, ParallelOp::getWaitKeyword(), 176 waitOperands, waitOperandTypes, result))) 177 return failure(); 178 179 // num_gangs(value)? 180 numGangs = parseOptionalOperandAndType( 181 parser, ParallelOp::getNumGangsKeyword(), result); 182 if (numGangs.hasValue() && failed(*numGangs)) 183 return failure(); 184 185 // num_workers(value)? 186 numWorkers = parseOptionalOperandAndType( 187 parser, ParallelOp::getNumWorkersKeyword(), result); 188 if (numWorkers.hasValue() && failed(*numWorkers)) 189 return failure(); 190 191 // vector_length(value)? 192 vectorLength = parseOptionalOperandAndType( 193 parser, ParallelOp::getVectorLengthKeyword(), result); 194 if (vectorLength.hasValue() && failed(*vectorLength)) 195 return failure(); 196 197 // if()? 198 if (failed(parseOptionalOperand(parser, ParallelOp::getIfKeyword(), ifCond, 199 i1Type, hasIfCond, result))) 200 return failure(); 201 202 // self()? 203 if (failed(parseOptionalOperand(parser, ParallelOp::getSelfKeyword(), 204 selfCond, i1Type, hasSelfCond, result))) 205 return failure(); 206 207 // reduction()? 208 if (failed(parseOperandList(parser, ParallelOp::getReductionKeyword(), 209 reductionOperands, reductionOperandTypes, 210 result))) 211 return failure(); 212 213 // copy()? 214 if (failed(parseOperandList(parser, ParallelOp::getCopyKeyword(), 215 copyOperands, copyOperandTypes, result))) 216 return failure(); 217 218 // copyin()? 219 if (failed(parseOperandList(parser, ParallelOp::getCopyinKeyword(), 220 copyinOperands, copyinOperandTypes, result))) 221 return failure(); 222 223 // copyin_readonly()? 224 if (failed(parseOperandList(parser, ParallelOp::getCopyinReadonlyKeyword(), 225 copyinReadonlyOperands, 226 copyinReadonlyOperandTypes, result))) 227 return failure(); 228 229 // copyout()? 230 if (failed(parseOperandList(parser, ParallelOp::getCopyoutKeyword(), 231 copyoutOperands, copyoutOperandTypes, result))) 232 return failure(); 233 234 // copyout_zero()? 235 if (failed(parseOperandList(parser, ParallelOp::getCopyoutZeroKeyword(), 236 copyoutZeroOperands, copyoutZeroOperandTypes, 237 result))) 238 return failure(); 239 240 // create()? 241 if (failed(parseOperandList(parser, ParallelOp::getCreateKeyword(), 242 createOperands, createOperandTypes, result))) 243 return failure(); 244 245 // create_zero()? 246 if (failed(parseOperandList(parser, ParallelOp::getCreateZeroKeyword(), 247 createZeroOperands, createZeroOperandTypes, 248 result))) 249 return failure(); 250 251 // no_create()? 252 if (failed(parseOperandList(parser, ParallelOp::getNoCreateKeyword(), 253 noCreateOperands, noCreateOperandTypes, result))) 254 return failure(); 255 256 // present()? 257 if (failed(parseOperandList(parser, ParallelOp::getPresentKeyword(), 258 presentOperands, presentOperandTypes, result))) 259 return failure(); 260 261 // deviceptr()? 262 if (failed(parseOperandList(parser, ParallelOp::getDevicePtrKeyword(), 263 devicePtrOperands, deviceptrOperandTypes, 264 result))) 265 return failure(); 266 267 // attach()? 268 if (failed(parseOperandList(parser, ParallelOp::getAttachKeyword(), 269 attachOperands, attachOperandTypes, result))) 270 return failure(); 271 272 // private()? 273 if (failed(parseOperandList(parser, ParallelOp::getPrivateKeyword(), 274 privateOperands, privateOperandTypes, result))) 275 return failure(); 276 277 // firstprivate()? 278 if (failed(parseOperandList(parser, ParallelOp::getFirstPrivateKeyword(), 279 firstprivateOperands, firstprivateOperandTypes, 280 result))) 281 return failure(); 282 283 // Parallel op region 284 if (failed(parseRegions<ParallelOp>(parser, result))) 285 return failure(); 286 287 result.addAttribute( 288 ParallelOp::getOperandSegmentSizeAttr(), 289 builder.getI32VectorAttr( 290 {static_cast<int32_t>(async.hasValue() ? 1 : 0), 291 static_cast<int32_t>(waitOperands.size()), 292 static_cast<int32_t>(numGangs.hasValue() ? 1 : 0), 293 static_cast<int32_t>(numWorkers.hasValue() ? 1 : 0), 294 static_cast<int32_t>(vectorLength.hasValue() ? 1 : 0), 295 static_cast<int32_t>(hasIfCond ? 1 : 0), 296 static_cast<int32_t>(hasSelfCond ? 1 : 0), 297 static_cast<int32_t>(reductionOperands.size()), 298 static_cast<int32_t>(copyOperands.size()), 299 static_cast<int32_t>(copyinOperands.size()), 300 static_cast<int32_t>(copyinReadonlyOperands.size()), 301 static_cast<int32_t>(copyoutOperands.size()), 302 static_cast<int32_t>(copyoutZeroOperands.size()), 303 static_cast<int32_t>(createOperands.size()), 304 static_cast<int32_t>(createZeroOperands.size()), 305 static_cast<int32_t>(noCreateOperands.size()), 306 static_cast<int32_t>(presentOperands.size()), 307 static_cast<int32_t>(devicePtrOperands.size()), 308 static_cast<int32_t>(attachOperands.size()), 309 static_cast<int32_t>(privateOperands.size()), 310 static_cast<int32_t>(firstprivateOperands.size())})); 311 312 // Additional attributes 313 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 314 return failure(); 315 316 return success(); 317 } 318 319 static void print(OpAsmPrinter &printer, ParallelOp &op) { 320 printer << ParallelOp::getOperationName(); 321 322 // async()? 323 if (Value async = op.async()) 324 printer << " " << ParallelOp::getAsyncKeyword() << "(" << async << ": " 325 << async.getType() << ")"; 326 327 // wait()? 328 printOperandList(op.waitOperands(), ParallelOp::getWaitKeyword(), printer); 329 330 // num_gangs()? 331 if (Value numGangs = op.numGangs()) 332 printer << " " << ParallelOp::getNumGangsKeyword() << "(" << numGangs 333 << ": " << numGangs.getType() << ")"; 334 335 // num_workers()? 336 if (Value numWorkers = op.numWorkers()) 337 printer << " " << ParallelOp::getNumWorkersKeyword() << "(" << numWorkers 338 << ": " << numWorkers.getType() << ")"; 339 340 // vector_length()? 341 if (Value vectorLength = op.vectorLength()) 342 printer << " " << ParallelOp::getVectorLengthKeyword() << "(" 343 << vectorLength << ": " << vectorLength.getType() << ")"; 344 345 // if()? 346 if (Value ifCond = op.ifCond()) 347 printer << " " << ParallelOp::getIfKeyword() << "(" << ifCond << ")"; 348 349 // self()? 350 if (Value selfCond = op.selfCond()) 351 printer << " " << ParallelOp::getSelfKeyword() << "(" << selfCond << ")"; 352 353 // reduction()? 354 printOperandList(op.reductionOperands(), ParallelOp::getReductionKeyword(), 355 printer); 356 357 // copy()? 358 printOperandList(op.copyOperands(), ParallelOp::getCopyKeyword(), printer); 359 360 // copyin()? 361 printOperandList(op.copyinOperands(), ParallelOp::getCopyinKeyword(), 362 printer); 363 364 // copyin_readonly()? 365 printOperandList(op.copyinReadonlyOperands(), 366 ParallelOp::getCopyinReadonlyKeyword(), printer); 367 368 // copyout()? 369 printOperandList(op.copyoutOperands(), ParallelOp::getCopyoutKeyword(), 370 printer); 371 372 // copyout_zero()? 373 printOperandList(op.copyoutZeroOperands(), 374 ParallelOp::getCopyoutZeroKeyword(), printer); 375 376 // create()? 377 printOperandList(op.createOperands(), ParallelOp::getCreateKeyword(), 378 printer); 379 380 // create_zero()? 381 printOperandList(op.createZeroOperands(), ParallelOp::getCreateZeroKeyword(), 382 printer); 383 384 // no_create()? 385 printOperandList(op.noCreateOperands(), ParallelOp::getNoCreateKeyword(), 386 printer); 387 388 // present()? 389 printOperandList(op.presentOperands(), ParallelOp::getPresentKeyword(), 390 printer); 391 392 // deviceptr()? 393 printOperandList(op.devicePtrOperands(), ParallelOp::getDevicePtrKeyword(), 394 printer); 395 396 // attach()? 397 printOperandList(op.attachOperands(), ParallelOp::getAttachKeyword(), 398 printer); 399 400 // private()? 401 printOperandList(op.gangPrivateOperands(), ParallelOp::getPrivateKeyword(), 402 printer); 403 404 // firstprivate()? 405 printOperandList(op.gangFirstPrivateOperands(), 406 ParallelOp::getFirstPrivateKeyword(), printer); 407 408 printer.printRegion(op.region(), 409 /*printEntryBlockArgs=*/false, 410 /*printBlockTerminators=*/true); 411 printer.printOptionalAttrDictWithKeyword( 412 op.getAttrs(), ParallelOp::getOperandSegmentSizeAttr()); 413 } 414 415 //===----------------------------------------------------------------------===// 416 // DataOp 417 //===----------------------------------------------------------------------===// 418 419 /// Parse acc.data operation 420 /// operation := `acc.parallel` (`present` `(` value-list `)`)? 421 /// (`copy` `(` value-list `)`)? 422 /// (`copyin` `(` value-list `)`)? 423 /// (`copyin_readonly` `(` value-list `)`)? 424 /// (`copyout` `(` value-list `)`)? 425 /// (`copyout_zero` `(` value-list `)`)? 426 /// (`create` `(` value-list `)`)? 427 /// (`create_zero` `(` value-list `)`)? 428 /// (`no_create` `(` value-list `)`)? 429 /// (`delete` `(` value-list `)`)? 430 /// (`attach` `(` value-list `)`)? 431 /// (`detach` `(` value-list `)`)? 432 /// region attr-dict? 433 static ParseResult parseDataOp(OpAsmParser &parser, OperationState &result) { 434 Builder &builder = parser.getBuilder(); 435 SmallVector<OpAsmParser::OperandType, 2> presentOperands, copyOperands, 436 copyinOperands, copyinReadonlyOperands, copyoutOperands, 437 copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands, 438 deleteOperands, attachOperands, detachOperands; 439 SmallVector<Type, 2> presentOperandTypes, copyOperandTypes, 440 copyinOperandTypes, copyinReadonlyOperandTypes, copyoutOperandTypes, 441 copyoutZeroOperandTypes, createOperandTypes, createZeroOperandTypes, 442 noCreateOperandTypes, deleteOperandTypes, attachOperandTypes, 443 detachOperandTypes; 444 445 // present(value-list)? 446 if (failed(parseOperandList(parser, DataOp::getPresentKeyword(), 447 presentOperands, presentOperandTypes, result))) 448 return failure(); 449 450 // copy(value-list)? 451 if (failed(parseOperandList(parser, DataOp::getCopyKeyword(), copyOperands, 452 copyOperandTypes, result))) 453 return failure(); 454 455 // copyin(value-list)? 456 if (failed(parseOperandList(parser, DataOp::getCopyinKeyword(), 457 copyinOperands, copyinOperandTypes, result))) 458 return failure(); 459 460 // copyin_readonly(value-list)? 461 if (failed(parseOperandList(parser, DataOp::getCopyinReadonlyKeyword(), 462 copyinReadonlyOperands, copyinOperandTypes, 463 result))) 464 return failure(); 465 466 // copyout(value-list)? 467 if (failed(parseOperandList(parser, DataOp::getCopyoutKeyword(), 468 copyoutOperands, copyoutOperandTypes, result))) 469 return failure(); 470 471 // copyout_zero(value-list)? 472 if (failed(parseOperandList(parser, DataOp::getCopyoutZeroKeyword(), 473 copyoutZeroOperands, copyoutZeroOperandTypes, 474 result))) 475 return failure(); 476 477 // create(value-list)? 478 if (failed(parseOperandList(parser, DataOp::getCreateKeyword(), 479 createOperands, createOperandTypes, result))) 480 return failure(); 481 482 // create_zero(value-list)? 483 if (failed(parseOperandList(parser, DataOp::getCreateZeroKeyword(), 484 createZeroOperands, createZeroOperandTypes, 485 result))) 486 return failure(); 487 488 // no_create(value-list)? 489 if (failed(parseOperandList(parser, DataOp::getNoCreateKeyword(), 490 noCreateOperands, noCreateOperandTypes, result))) 491 return failure(); 492 493 // delete(value-list)? 494 if (failed(parseOperandList(parser, DataOp::getDeleteKeyword(), 495 deleteOperands, deleteOperandTypes, result))) 496 return failure(); 497 498 // attach(value-list)? 499 if (failed(parseOperandList(parser, DataOp::getAttachKeyword(), 500 attachOperands, attachOperandTypes, result))) 501 return failure(); 502 503 // detach(value-list)? 504 if (failed(parseOperandList(parser, DataOp::getDetachKeyword(), 505 detachOperands, detachOperandTypes, result))) 506 return failure(); 507 508 // Data op region 509 if (failed(parseRegions<ParallelOp>(parser, result))) 510 return failure(); 511 512 result.addAttribute(ParallelOp::getOperandSegmentSizeAttr(), 513 builder.getI32VectorAttr( 514 {static_cast<int32_t>(presentOperands.size()), 515 static_cast<int32_t>(copyOperands.size()), 516 static_cast<int32_t>(copyinOperands.size()), 517 static_cast<int32_t>(copyinReadonlyOperands.size()), 518 static_cast<int32_t>(copyoutOperands.size()), 519 static_cast<int32_t>(copyoutZeroOperands.size()), 520 static_cast<int32_t>(createOperands.size()), 521 static_cast<int32_t>(createZeroOperands.size()), 522 static_cast<int32_t>(noCreateOperands.size()), 523 static_cast<int32_t>(deleteOperands.size()), 524 static_cast<int32_t>(attachOperands.size()), 525 static_cast<int32_t>(detachOperands.size())})); 526 527 // Additional attributes 528 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 529 return failure(); 530 531 return success(); 532 } 533 534 static void print(OpAsmPrinter &printer, DataOp &op) { 535 printer << DataOp::getOperationName(); 536 537 // present(value-list)? 538 printOperandList(op.presentOperands(), DataOp::getPresentKeyword(), printer); 539 540 // copy(value-list)? 541 printOperandList(op.copyOperands(), DataOp::getCopyKeyword(), printer); 542 543 // copyin(value-list)? 544 printOperandList(op.copyinOperands(), DataOp::getCopyinKeyword(), printer); 545 546 // copyin_readonly(value-list)? 547 printOperandList(op.copyinReadonlyOperands(), 548 DataOp::getCopyinReadonlyKeyword(), printer); 549 550 // copyout(value-list)? 551 printOperandList(op.copyoutOperands(), DataOp::getCopyoutKeyword(), printer); 552 553 // copyout(value-list)? 554 printOperandList(op.copyoutZeroOperands(), DataOp::getCopyoutZeroKeyword(), 555 printer); 556 557 // create(value-list)? 558 printOperandList(op.createOperands(), DataOp::getCreateKeyword(), printer); 559 560 // create_zero(value-list)? 561 printOperandList(op.createZeroOperands(), DataOp::getCreateZeroKeyword(), 562 printer); 563 564 // no_create(value-list)? 565 printOperandList(op.noCreateOperands(), DataOp::getNoCreateKeyword(), 566 printer); 567 568 // delete(value-list)? 569 printOperandList(op.deleteOperands(), DataOp::getDeleteKeyword(), printer); 570 571 // attach(value-list)? 572 printOperandList(op.attachOperands(), DataOp::getAttachKeyword(), printer); 573 574 // detach(value-list)? 575 printOperandList(op.detachOperands(), DataOp::getDetachKeyword(), printer); 576 577 printer.printRegion(op.region(), 578 /*printEntryBlockArgs=*/false, 579 /*printBlockTerminators=*/true); 580 printer.printOptionalAttrDictWithKeyword( 581 op.getAttrs(), ParallelOp::getOperandSegmentSizeAttr()); 582 } 583 584 //===----------------------------------------------------------------------===// 585 // LoopOp 586 //===----------------------------------------------------------------------===// 587 588 /// Parse acc.loop operation 589 /// operation := `acc.loop` 590 /// (`gang` ( `(` (`num=` value)? (`,` `static=` value `)`)? )? )? 591 /// (`vector` ( `(` value `)` )? )? (`worker` (`(` value `)`)? )? 592 /// (`vector_length` `(` value `)`)? 593 /// (`tile` `(` value-list `)`)? 594 /// (`private` `(` value-list `)`)? 595 /// (`reduction` `(` value-list `)`)? 596 /// region attr-dict? 597 static ParseResult parseLoopOp(OpAsmParser &parser, OperationState &result) { 598 Builder &builder = parser.getBuilder(); 599 unsigned executionMapping = OpenACCExecMapping::NONE; 600 SmallVector<Type, 8> operandTypes; 601 SmallVector<OpAsmParser::OperandType, 8> privateOperands, reductionOperands; 602 SmallVector<OpAsmParser::OperandType, 8> tileOperands; 603 bool hasWorkerNum = false, hasVectorLength = false, hasGangNum = false; 604 bool hasGangStatic = false; 605 OpAsmParser::OperandType workerNum, vectorLength, gangNum, gangStatic; 606 Type gangNumType, gangStaticType, workerType, vectorLengthType; 607 608 // gang? 609 if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangKeyword()))) 610 executionMapping |= OpenACCExecMapping::GANG; 611 612 // optional gang operand 613 if (succeeded(parser.parseOptionalLParen())) { 614 if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangNumKeyword()))) { 615 hasGangNum = true; 616 parser.parseEqual(); 617 if (parser.parseOperand(gangNum) || parser.parseColonType(gangNumType) || 618 parser.resolveOperand(gangNum, gangNumType, result.operands)) { 619 return failure(); 620 } 621 } 622 parser.parseOptionalComma(); 623 if (succeeded( 624 parser.parseOptionalKeyword(LoopOp::getGangStaticKeyword()))) { 625 hasGangStatic = true; 626 parser.parseEqual(); 627 if (parser.parseOperand(gangStatic) || 628 parser.parseColonType(gangStaticType) || 629 parser.resolveOperand(gangStatic, gangStaticType, result.operands)) { 630 return failure(); 631 } 632 } 633 if (failed(parser.parseRParen())) 634 return failure(); 635 } 636 637 // worker? 638 if (succeeded(parser.parseOptionalKeyword(LoopOp::getWorkerKeyword()))) 639 executionMapping |= OpenACCExecMapping::WORKER; 640 641 // optional worker operand 642 if (succeeded(parser.parseOptionalLParen())) { 643 hasWorkerNum = true; 644 if (parser.parseOperand(workerNum) || parser.parseColonType(workerType) || 645 parser.resolveOperand(workerNum, workerType, result.operands) || 646 parser.parseRParen()) { 647 return failure(); 648 } 649 } 650 651 // vector? 652 if (succeeded(parser.parseOptionalKeyword(LoopOp::getVectorKeyword()))) 653 executionMapping |= OpenACCExecMapping::VECTOR; 654 655 // optional vector operand 656 if (succeeded(parser.parseOptionalLParen())) { 657 hasVectorLength = true; 658 if (parser.parseOperand(vectorLength) || 659 parser.parseColonType(vectorLengthType) || 660 parser.resolveOperand(vectorLength, vectorLengthType, 661 result.operands) || 662 parser.parseRParen()) { 663 return failure(); 664 } 665 } 666 667 // tile()? 668 if (failed(parseOperandList(parser, LoopOp::getTileKeyword(), tileOperands, 669 operandTypes, result))) 670 return failure(); 671 672 // private()? 673 if (failed(parseOperandList(parser, LoopOp::getPrivateKeyword(), 674 privateOperands, operandTypes, result))) 675 return failure(); 676 677 // reduction()? 678 if (failed(parseOperandList(parser, LoopOp::getReductionKeyword(), 679 reductionOperands, operandTypes, result))) 680 return failure(); 681 682 if (executionMapping != acc::OpenACCExecMapping::NONE) 683 result.addAttribute(LoopOp::getExecutionMappingAttrName(), 684 builder.getI64IntegerAttr(executionMapping)); 685 686 // Parse optional results in case there is a reduce. 687 if (parser.parseOptionalArrowTypeList(result.types)) 688 return failure(); 689 690 if (failed(parseRegions<LoopOp>(parser, result))) 691 return failure(); 692 693 result.addAttribute(LoopOp::getOperandSegmentSizeAttr(), 694 builder.getI32VectorAttr( 695 {static_cast<int32_t>(hasGangNum ? 1 : 0), 696 static_cast<int32_t>(hasGangStatic ? 1 : 0), 697 static_cast<int32_t>(hasWorkerNum ? 1 : 0), 698 static_cast<int32_t>(hasVectorLength ? 1 : 0), 699 static_cast<int32_t>(tileOperands.size()), 700 static_cast<int32_t>(privateOperands.size()), 701 static_cast<int32_t>(reductionOperands.size())})); 702 703 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 704 return failure(); 705 706 return success(); 707 } 708 709 static void print(OpAsmPrinter &printer, LoopOp &op) { 710 printer << LoopOp::getOperationName(); 711 712 unsigned execMapping = op.exec_mapping(); 713 if (execMapping & OpenACCExecMapping::GANG) { 714 printer << " " << LoopOp::getGangKeyword(); 715 Value gangNum = op.gangNum(); 716 Value gangStatic = op.gangStatic(); 717 718 // Print optional gang operands 719 if (gangNum || gangStatic) { 720 printer << "("; 721 if (gangNum) { 722 printer << LoopOp::getGangNumKeyword() << "=" << gangNum << ": " 723 << gangNum.getType(); 724 if (gangStatic) 725 printer << ", "; 726 } 727 if (gangStatic) 728 printer << LoopOp::getGangStaticKeyword() << "=" << gangStatic << ": " 729 << gangStatic.getType(); 730 printer << ")"; 731 } 732 } 733 734 if (execMapping & OpenACCExecMapping::WORKER) { 735 printer << " " << LoopOp::getWorkerKeyword(); 736 737 // Print optional worker operand if present 738 if (Value workerNum = op.workerNum()) 739 printer << "(" << workerNum << ": " << workerNum.getType() << ")"; 740 } 741 742 if (execMapping & OpenACCExecMapping::VECTOR) { 743 printer << " " << LoopOp::getVectorKeyword(); 744 745 // Print optional vector operand if present 746 if (Value vectorLength = op.vectorLength()) 747 printer << "(" << vectorLength << ": " << vectorLength.getType() << ")"; 748 } 749 750 // tile()? 751 printOperandList(op.tileOperands(), LoopOp::getTileKeyword(), printer); 752 753 // private()? 754 printOperandList(op.privateOperands(), LoopOp::getPrivateKeyword(), printer); 755 756 // reduction()? 757 printOperandList(op.reductionOperands(), LoopOp::getReductionKeyword(), 758 printer); 759 760 if (op.getNumResults() > 0) 761 printer << " -> (" << op.getResultTypes() << ")"; 762 763 printer.printRegion(op.region(), 764 /*printEntryBlockArgs=*/false, 765 /*printBlockTerminators=*/true); 766 767 printer.printOptionalAttrDictWithKeyword( 768 op.getAttrs(), {LoopOp::getExecutionMappingAttrName(), 769 LoopOp::getOperandSegmentSizeAttr()}); 770 } 771 772 static LogicalResult verifyLoopOp(acc::LoopOp loopOp) { 773 // auto, independent and seq attribute are mutually exclusive. 774 if ((loopOp.auto_() && (loopOp.independent() || loopOp.seq())) || 775 (loopOp.independent() && loopOp.seq())) { 776 loopOp.emitError("only one of " + acc::LoopOp::getAutoAttrName() + ", " + 777 acc::LoopOp::getIndependentAttrName() + ", " + 778 acc::LoopOp::getSeqAttrName() + 779 " can be present at the same time"); 780 return failure(); 781 } 782 783 // Gang, worker and vector are incompatible with seq. 784 if (loopOp.seq() && loopOp.exec_mapping() != OpenACCExecMapping::NONE) { 785 loopOp.emitError("gang, worker or vector cannot appear with the seq attr"); 786 return failure(); 787 } 788 789 // Check non-empty body(). 790 if (loopOp.region().empty()) { 791 loopOp.emitError("expected non-empty body."); 792 return failure(); 793 } 794 795 return success(); 796 } 797 798 #define GET_OP_CLASSES 799 #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc" 800