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 //===----------------------------------------------------------------------===// 105 // ParallelOp 106 //===----------------------------------------------------------------------===// 107 108 /// Parse acc.parallel operation 109 /// operation := `acc.parallel` `async` `(` index `)`? 110 /// `wait` `(` index-list `)`? 111 /// `num_gangs` `(` value `)`? 112 /// `num_workers` `(` value `)`? 113 /// `vector_length` `(` value `)`? 114 /// `if` `(` value `)`? 115 /// `self` `(` value `)`? 116 /// `reduction` `(` value-list `)`? 117 /// `copy` `(` value-list `)`? 118 /// `copyin` `(` value-list `)`? 119 /// `copyout` `(` value-list `)`? 120 /// `create` `(` value-list `)`? 121 /// `no_create` `(` value-list `)`? 122 /// `present` `(` value-list `)`? 123 /// `deviceptr` `(` value-list `)`? 124 /// `attach` `(` value-list `)`? 125 /// `private` `(` value-list `)`? 126 /// `firstprivate` `(` value-list `)`? 127 /// region attr-dict? 128 static ParseResult parseParallelOp(OpAsmParser &parser, 129 OperationState &result) { 130 Builder &builder = parser.getBuilder(); 131 SmallVector<OpAsmParser::OperandType, 8> privateOperands, 132 firstprivateOperands, createOperands, copyOperands, copyinOperands, 133 copyoutOperands, noCreateOperands, presentOperands, devicePtrOperands, 134 attachOperands, waitOperands, reductionOperands; 135 SmallVector<Type, 8> operandTypes; 136 OpAsmParser::OperandType async, numGangs, numWorkers, vectorLength, ifCond, 137 selfCond; 138 bool hasAsync = false, hasNumGangs = false, hasNumWorkers = false; 139 bool hasVectorLength = false, hasIfCond = false, hasSelfCond = false; 140 141 Type indexType = builder.getIndexType(); 142 Type i1Type = builder.getI1Type(); 143 144 // async()? 145 if (failed(parseOptionalOperand(parser, ParallelOp::getAsyncKeyword(), async, 146 indexType, hasAsync, result))) 147 return failure(); 148 149 // wait()? 150 if (failed(parseOperandList(parser, ParallelOp::getWaitKeyword(), 151 waitOperands, operandTypes, result))) 152 return failure(); 153 154 // num_gangs(value)? 155 if (failed(parseOptionalOperand(parser, ParallelOp::getNumGangsKeyword(), 156 numGangs, indexType, hasNumGangs, result))) 157 return failure(); 158 159 // num_workers(value)? 160 if (failed(parseOptionalOperand(parser, ParallelOp::getNumWorkersKeyword(), 161 numWorkers, indexType, hasNumWorkers, 162 result))) 163 return failure(); 164 165 // vector_length(value)? 166 if (failed(parseOptionalOperand(parser, ParallelOp::getVectorLengthKeyword(), 167 vectorLength, indexType, hasVectorLength, 168 result))) 169 return failure(); 170 171 // if()? 172 if (failed(parseOptionalOperand(parser, ParallelOp::getIfKeyword(), ifCond, 173 i1Type, hasIfCond, result))) 174 return failure(); 175 176 // self()? 177 if (failed(parseOptionalOperand(parser, ParallelOp::getSelfKeyword(), 178 selfCond, i1Type, hasSelfCond, result))) 179 return failure(); 180 181 // reduction()? 182 if (failed(parseOperandList(parser, ParallelOp::getReductionKeyword(), 183 reductionOperands, operandTypes, result))) 184 return failure(); 185 186 // copy()? 187 if (failed(parseOperandList(parser, ParallelOp::getCopyKeyword(), 188 copyOperands, operandTypes, result))) 189 return failure(); 190 191 // copyin()? 192 if (failed(parseOperandList(parser, ParallelOp::getCopyinKeyword(), 193 copyinOperands, operandTypes, result))) 194 return failure(); 195 196 // copyout()? 197 if (failed(parseOperandList(parser, ParallelOp::getCopyoutKeyword(), 198 copyoutOperands, operandTypes, result))) 199 return failure(); 200 201 // create()? 202 if (failed(parseOperandList(parser, ParallelOp::getCreateKeyword(), 203 createOperands, operandTypes, result))) 204 return failure(); 205 206 // no_create()? 207 if (failed(parseOperandList(parser, ParallelOp::getNoCreateKeyword(), 208 noCreateOperands, operandTypes, result))) 209 return failure(); 210 211 // present()? 212 if (failed(parseOperandList(parser, ParallelOp::getPresentKeyword(), 213 presentOperands, operandTypes, result))) 214 return failure(); 215 216 // deviceptr()? 217 if (failed(parseOperandList(parser, ParallelOp::getDevicePtrKeyword(), 218 devicePtrOperands, operandTypes, result))) 219 return failure(); 220 221 // attach()? 222 if (failed(parseOperandList(parser, ParallelOp::getAttachKeyword(), 223 attachOperands, operandTypes, result))) 224 return failure(); 225 226 // private()? 227 if (failed(parseOperandList(parser, ParallelOp::getPrivateKeyword(), 228 privateOperands, operandTypes, result))) 229 return failure(); 230 231 // firstprivate()? 232 if (failed(parseOperandList(parser, ParallelOp::getFirstPrivateKeyword(), 233 firstprivateOperands, operandTypes, result))) 234 return failure(); 235 236 // Parallel op region 237 if (failed(parseRegions<ParallelOp>(parser, result))) 238 return failure(); 239 240 result.addAttribute(ParallelOp::getOperandSegmentSizeAttr(), 241 builder.getI32VectorAttr( 242 {static_cast<int32_t>(hasAsync ? 1 : 0), 243 static_cast<int32_t>(waitOperands.size()), 244 static_cast<int32_t>(hasNumGangs ? 1 : 0), 245 static_cast<int32_t>(hasNumWorkers ? 1 : 0), 246 static_cast<int32_t>(hasVectorLength ? 1 : 0), 247 static_cast<int32_t>(hasIfCond ? 1 : 0), 248 static_cast<int32_t>(hasSelfCond ? 1 : 0), 249 static_cast<int32_t>(reductionOperands.size()), 250 static_cast<int32_t>(copyOperands.size()), 251 static_cast<int32_t>(copyinOperands.size()), 252 static_cast<int32_t>(copyoutOperands.size()), 253 static_cast<int32_t>(createOperands.size()), 254 static_cast<int32_t>(noCreateOperands.size()), 255 static_cast<int32_t>(presentOperands.size()), 256 static_cast<int32_t>(devicePtrOperands.size()), 257 static_cast<int32_t>(attachOperands.size()), 258 static_cast<int32_t>(privateOperands.size()), 259 static_cast<int32_t>(firstprivateOperands.size())})); 260 261 // Additional attributes 262 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 263 return failure(); 264 265 return success(); 266 } 267 268 static void print(OpAsmPrinter &printer, ParallelOp &op) { 269 printer << ParallelOp::getOperationName(); 270 271 // async()? 272 if (Value async = op.async()) 273 printer << " " << ParallelOp::getAsyncKeyword() << "(" << async << ")"; 274 275 // wait()? 276 printOperandList(op.waitOperands(), ParallelOp::getWaitKeyword(), printer); 277 278 // num_gangs()? 279 if (Value numGangs = op.numGangs()) 280 printer << " " << ParallelOp::getNumGangsKeyword() << "(" << numGangs 281 << ")"; 282 283 // num_workers()? 284 if (Value numWorkers = op.numWorkers()) 285 printer << " " << ParallelOp::getNumWorkersKeyword() << "(" << numWorkers 286 << ")"; 287 288 // vector_length()? 289 if (Value vectorLength = op.vectorLength()) 290 printer << " " << ParallelOp::getVectorLengthKeyword() << "(" 291 << vectorLength << ")"; 292 293 // if()? 294 if (Value ifCond = op.ifCond()) 295 printer << " " << ParallelOp::getIfKeyword() << "(" << ifCond << ")"; 296 297 // self()? 298 if (Value selfCond = op.selfCond()) 299 printer << " " << ParallelOp::getSelfKeyword() << "(" << selfCond << ")"; 300 301 // reduction()? 302 printOperandList(op.reductionOperands(), ParallelOp::getReductionKeyword(), 303 printer); 304 305 // copy()? 306 printOperandList(op.copyOperands(), ParallelOp::getCopyKeyword(), printer); 307 308 // copyin()? 309 printOperandList(op.copyinOperands(), ParallelOp::getCopyinKeyword(), 310 printer); 311 312 // copyout()? 313 printOperandList(op.copyoutOperands(), ParallelOp::getCopyoutKeyword(), 314 printer); 315 316 // create()? 317 printOperandList(op.createOperands(), ParallelOp::getCreateKeyword(), 318 printer); 319 320 // no_create()? 321 printOperandList(op.noCreateOperands(), ParallelOp::getNoCreateKeyword(), 322 printer); 323 324 // present()? 325 printOperandList(op.presentOperands(), ParallelOp::getPresentKeyword(), 326 printer); 327 328 // deviceptr()? 329 printOperandList(op.devicePtrOperands(), ParallelOp::getDevicePtrKeyword(), 330 printer); 331 332 // attach()? 333 printOperandList(op.attachOperands(), ParallelOp::getAttachKeyword(), 334 printer); 335 336 // private()? 337 printOperandList(op.gangPrivateOperands(), ParallelOp::getPrivateKeyword(), 338 printer); 339 340 // firstprivate()? 341 printOperandList(op.gangFirstPrivateOperands(), 342 ParallelOp::getFirstPrivateKeyword(), printer); 343 344 printer.printRegion(op.region(), 345 /*printEntryBlockArgs=*/false, 346 /*printBlockTerminators=*/true); 347 printer.printOptionalAttrDictWithKeyword( 348 op.getAttrs(), ParallelOp::getOperandSegmentSizeAttr()); 349 } 350 351 //===----------------------------------------------------------------------===// 352 // DataOp 353 //===----------------------------------------------------------------------===// 354 355 /// Parse acc.data operation 356 /// operation := `acc.parallel` `present` `(` value-list `)`? 357 /// `copy` `(` value-list `)`? 358 /// `copyin` `(` value-list `)`? 359 /// `copyout` `(` value-list `)`? 360 /// `create` `(` value-list `)`? 361 /// `no_create` `(` value-list `)`? 362 /// `delete` `(` value-list `)`? 363 /// `attach` `(` value-list `)`? 364 /// `detach` `(` value-list `)`? 365 /// region attr-dict? 366 static ParseResult parseDataOp(OpAsmParser &parser, OperationState &result) { 367 Builder &builder = parser.getBuilder(); 368 SmallVector<OpAsmParser::OperandType, 8> presentOperands, copyOperands, 369 copyinOperands, copyoutOperands, createOperands, noCreateOperands, 370 deleteOperands, attachOperands, detachOperands; 371 SmallVector<Type, 8> operandsTypes; 372 373 // present(value-list)? 374 if (failed(parseOperandList(parser, DataOp::getPresentKeyword(), 375 presentOperands, operandsTypes, result))) 376 return failure(); 377 378 // copy(value-list)? 379 if (failed(parseOperandList(parser, DataOp::getCopyKeyword(), copyOperands, 380 operandsTypes, result))) 381 return failure(); 382 383 // copyin(value-list)? 384 if (failed(parseOperandList(parser, DataOp::getCopyinKeyword(), 385 copyinOperands, operandsTypes, result))) 386 return failure(); 387 388 // copyout(value-list)? 389 if (failed(parseOperandList(parser, DataOp::getCopyoutKeyword(), 390 copyoutOperands, operandsTypes, result))) 391 return failure(); 392 393 // create(value-list)? 394 if (failed(parseOperandList(parser, DataOp::getCreateKeyword(), 395 createOperands, operandsTypes, result))) 396 return failure(); 397 398 // no_create(value-list)? 399 if (failed(parseOperandList(parser, DataOp::getCreateKeyword(), 400 noCreateOperands, operandsTypes, result))) 401 return failure(); 402 403 // delete(value-list)? 404 if (failed(parseOperandList(parser, DataOp::getDeleteKeyword(), 405 deleteOperands, operandsTypes, result))) 406 return failure(); 407 408 // attach(value-list)? 409 if (failed(parseOperandList(parser, DataOp::getAttachKeyword(), 410 attachOperands, operandsTypes, result))) 411 return failure(); 412 413 // detach(value-list)? 414 if (failed(parseOperandList(parser, DataOp::getDetachKeyword(), 415 detachOperands, operandsTypes, result))) 416 return failure(); 417 418 // Data op region 419 if (failed(parseRegions<ParallelOp>(parser, result))) 420 return failure(); 421 422 result.addAttribute( 423 ParallelOp::getOperandSegmentSizeAttr(), 424 builder.getI32VectorAttr({static_cast<int32_t>(presentOperands.size()), 425 static_cast<int32_t>(copyOperands.size()), 426 static_cast<int32_t>(copyinOperands.size()), 427 static_cast<int32_t>(copyoutOperands.size()), 428 static_cast<int32_t>(createOperands.size()), 429 static_cast<int32_t>(noCreateOperands.size()), 430 static_cast<int32_t>(deleteOperands.size()), 431 static_cast<int32_t>(attachOperands.size()), 432 static_cast<int32_t>(detachOperands.size())})); 433 434 // Additional attributes 435 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 436 return failure(); 437 438 return success(); 439 } 440 441 static void print(OpAsmPrinter &printer, DataOp &op) { 442 printer << DataOp::getOperationName(); 443 444 // present(value-list)? 445 printOperandList(op.presentOperands(), DataOp::getPresentKeyword(), printer); 446 447 // copy(value-list)? 448 printOperandList(op.copyOperands(), DataOp::getCopyKeyword(), printer); 449 450 // copyin(value-list)? 451 printOperandList(op.copyinOperands(), DataOp::getCopyinKeyword(), printer); 452 453 // copyout(value-list)? 454 printOperandList(op.copyoutOperands(), DataOp::getCopyoutKeyword(), printer); 455 456 // create(value-list)? 457 printOperandList(op.createOperands(), DataOp::getCreateKeyword(), printer); 458 459 // no_create(value-list)? 460 printOperandList(op.noCreateOperands(), DataOp::getNoCreateKeyword(), 461 printer); 462 463 // delete(value-list)? 464 printOperandList(op.deleteOperands(), DataOp::getDeleteKeyword(), printer); 465 466 // attach(value-list)? 467 printOperandList(op.attachOperands(), DataOp::getAttachKeyword(), printer); 468 469 // detach(value-list)? 470 printOperandList(op.detachOperands(), DataOp::getDetachKeyword(), printer); 471 472 printer.printRegion(op.region(), 473 /*printEntryBlockArgs=*/false, 474 /*printBlockTerminators=*/true); 475 printer.printOptionalAttrDictWithKeyword( 476 op.getAttrs(), ParallelOp::getOperandSegmentSizeAttr()); 477 } 478 479 //===----------------------------------------------------------------------===// 480 // LoopOp 481 //===----------------------------------------------------------------------===// 482 483 /// Parse acc.loop operation 484 /// operation := `acc.loop` `gang`? `vector`? `worker`? 485 /// `private` `(` value-list `)`? 486 /// `reduction` `(` value-list `)`? 487 /// region attr-dict? 488 static ParseResult parseLoopOp(OpAsmParser &parser, OperationState &result) { 489 Builder &builder = parser.getBuilder(); 490 unsigned executionMapping = OpenACCExecMapping::NONE; 491 SmallVector<Type, 8> operandTypes; 492 SmallVector<OpAsmParser::OperandType, 8> privateOperands, reductionOperands; 493 SmallVector<OpAsmParser::OperandType, 8> tileOperands; 494 bool hasWorkerNum = false, hasVectorLength = false, hasGangNum = false; 495 bool hasGangStatic = false; 496 OpAsmParser::OperandType workerNum, vectorLength, gangNum, gangStatic; 497 Type intType = builder.getI64Type(); 498 499 // gang? 500 if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangKeyword()))) 501 executionMapping |= OpenACCExecMapping::GANG; 502 503 // optional gang operand 504 if (succeeded(parser.parseOptionalLParen())) { 505 if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangNumKeyword()))) { 506 hasGangNum = true; 507 parser.parseColon(); 508 if (parser.parseOperand(gangNum) || 509 parser.resolveOperand(gangNum, intType, result.operands)) { 510 return failure(); 511 } 512 } 513 parser.parseOptionalComma(); 514 if (succeeded( 515 parser.parseOptionalKeyword(LoopOp::getGangStaticKeyword()))) { 516 hasGangStatic = true; 517 parser.parseColon(); 518 if (parser.parseOperand(gangStatic) || 519 parser.resolveOperand(gangStatic, intType, result.operands)) { 520 return failure(); 521 } 522 } 523 if (failed(parser.parseRParen())) 524 return failure(); 525 } 526 527 // worker? 528 if (succeeded(parser.parseOptionalKeyword(LoopOp::getWorkerKeyword()))) 529 executionMapping |= OpenACCExecMapping::WORKER; 530 531 // optional worker operand 532 if (succeeded(parser.parseOptionalLParen())) { 533 hasWorkerNum = true; 534 if (parser.parseOperand(workerNum) || 535 parser.resolveOperand(workerNum, intType, result.operands) || 536 parser.parseRParen()) { 537 return failure(); 538 } 539 } 540 541 // vector? 542 if (succeeded(parser.parseOptionalKeyword(LoopOp::getVectorKeyword()))) 543 executionMapping |= OpenACCExecMapping::VECTOR; 544 545 // optional vector operand 546 if (succeeded(parser.parseOptionalLParen())) { 547 hasVectorLength = true; 548 if (parser.parseOperand(vectorLength) || 549 parser.resolveOperand(vectorLength, intType, result.operands) || 550 parser.parseRParen()) { 551 return failure(); 552 } 553 } 554 555 // tile()? 556 if (failed(parseOperandList(parser, LoopOp::getTileKeyword(), tileOperands, 557 operandTypes, result))) 558 return failure(); 559 560 // private()? 561 if (failed(parseOperandList(parser, LoopOp::getPrivateKeyword(), 562 privateOperands, operandTypes, result))) 563 return failure(); 564 565 // reduction()? 566 if (failed(parseOperandList(parser, LoopOp::getReductionKeyword(), 567 reductionOperands, operandTypes, result))) 568 return failure(); 569 570 if (executionMapping != acc::OpenACCExecMapping::NONE) 571 result.addAttribute(LoopOp::getExecutionMappingAttrName(), 572 builder.getI64IntegerAttr(executionMapping)); 573 574 // Parse optional results in case there is a reduce. 575 if (parser.parseOptionalArrowTypeList(result.types)) 576 return failure(); 577 578 if (failed(parseRegions<LoopOp>(parser, result))) 579 return failure(); 580 581 result.addAttribute(LoopOp::getOperandSegmentSizeAttr(), 582 builder.getI32VectorAttr( 583 {static_cast<int32_t>(hasGangNum ? 1 : 0), 584 static_cast<int32_t>(hasGangStatic ? 1 : 0), 585 static_cast<int32_t>(hasWorkerNum ? 1 : 0), 586 static_cast<int32_t>(hasVectorLength ? 1 : 0), 587 static_cast<int32_t>(tileOperands.size()), 588 static_cast<int32_t>(privateOperands.size()), 589 static_cast<int32_t>(reductionOperands.size())})); 590 591 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 592 return failure(); 593 594 return success(); 595 } 596 597 static void print(OpAsmPrinter &printer, LoopOp &op) { 598 printer << LoopOp::getOperationName(); 599 600 unsigned execMapping = op.exec_mapping(); 601 if (execMapping & OpenACCExecMapping::GANG) { 602 printer << " " << LoopOp::getGangKeyword(); 603 Value gangNum = op.gangNum(); 604 Value gangStatic = op.gangStatic(); 605 606 // Print optional gang operands 607 if (gangNum || gangStatic) { 608 printer << "("; 609 if (gangNum) { 610 printer << LoopOp::getGangNumKeyword() << ": " << gangNum; 611 if (gangStatic) 612 printer << ", "; 613 } 614 if (gangStatic) 615 printer << LoopOp::getGangStaticKeyword() << ": " << gangStatic; 616 printer << ")"; 617 } 618 } 619 620 if (execMapping & OpenACCExecMapping::WORKER) { 621 printer << " " << LoopOp::getWorkerKeyword(); 622 623 // Print optional worker operand if present 624 if (Value workerNum = op.workerNum()) 625 printer << "(" << workerNum << ")"; 626 } 627 628 if (execMapping & OpenACCExecMapping::VECTOR) { 629 printer << " " << LoopOp::getVectorKeyword(); 630 631 // Print optional vector operand if present 632 if (Value vectorLength = op.vectorLength()) 633 printer << "(" << vectorLength << ")"; 634 } 635 636 // tile()? 637 printOperandList(op.tileOperands(), LoopOp::getTileKeyword(), printer); 638 639 // private()? 640 printOperandList(op.privateOperands(), LoopOp::getPrivateKeyword(), printer); 641 642 // reduction()? 643 printOperandList(op.reductionOperands(), LoopOp::getReductionKeyword(), 644 printer); 645 646 if (op.getNumResults() > 0) 647 printer << " -> (" << op.getResultTypes() << ")"; 648 649 printer.printRegion(op.region(), 650 /*printEntryBlockArgs=*/false, 651 /*printBlockTerminators=*/true); 652 653 printer.printOptionalAttrDictWithKeyword( 654 op.getAttrs(), {LoopOp::getExecutionMappingAttrName(), 655 LoopOp::getOperandSegmentSizeAttr()}); 656 } 657 658 static LogicalResult verifyLoopOp(acc::LoopOp loopOp) { 659 // auto, independent and seq attribute are mutually exclusive. 660 if ((loopOp.auto_() && (loopOp.independent() || loopOp.seq())) || 661 (loopOp.independent() && loopOp.seq())) { 662 loopOp.emitError("only one of " + acc::LoopOp::getAutoAttrName() + ", " + 663 acc::LoopOp::getIndependentAttrName() + ", " + 664 acc::LoopOp::getSeqAttrName() + 665 " can be present at the same time"); 666 return failure(); 667 } 668 669 // Gang, worker and vector are incompatible with seq. 670 if (loopOp.seq() && loopOp.exec_mapping() != OpenACCExecMapping::NONE) { 671 loopOp.emitError("gang, worker or vector cannot appear with the seq attr"); 672 return failure(); 673 } 674 675 // Check non-empty body(). 676 if (loopOp.region().empty()) { 677 loopOp.emitError("expected non-empty body."); 678 return failure(); 679 } 680 681 return success(); 682 } 683 684 #define GET_OP_CLASSES 685 #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc" 686