1 //===- EmitC.cpp - EmitC Dialect ------------------------------------------===// 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 #include "mlir/Dialect/EmitC/IR/EmitC.h" 10 #include "mlir/Dialect/EmitC/IR/EmitCTraits.h" 11 #include "mlir/IR/Builders.h" 12 #include "mlir/IR/BuiltinAttributes.h" 13 #include "mlir/IR/BuiltinTypes.h" 14 #include "mlir/IR/DialectImplementation.h" 15 #include "mlir/IR/IRMapping.h" 16 #include "mlir/IR/Types.h" 17 #include "mlir/Interfaces/FunctionImplementation.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/TypeSwitch.h" 21 #include "llvm/Support/Casting.h" 22 23 using namespace mlir; 24 using namespace mlir::emitc; 25 26 #include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc" 27 28 //===----------------------------------------------------------------------===// 29 // EmitCDialect 30 //===----------------------------------------------------------------------===// 31 32 void EmitCDialect::initialize() { 33 addOperations< 34 #define GET_OP_LIST 35 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc" 36 >(); 37 addTypes< 38 #define GET_TYPEDEF_LIST 39 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc" 40 >(); 41 addAttributes< 42 #define GET_ATTRDEF_LIST 43 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc" 44 >(); 45 } 46 47 /// Materialize a single constant operation from a given attribute value with 48 /// the desired resultant type. 49 Operation *EmitCDialect::materializeConstant(OpBuilder &builder, 50 Attribute value, Type type, 51 Location loc) { 52 return builder.create<emitc::ConstantOp>(loc, type, value); 53 } 54 55 /// Default callback for builders of ops carrying a region. Inserts a yield 56 /// without arguments. 57 void mlir::emitc::buildTerminatedBody(OpBuilder &builder, Location loc) { 58 builder.create<emitc::YieldOp>(loc); 59 } 60 61 bool mlir::emitc::isSupportedEmitCType(Type type) { 62 if (llvm::isa<emitc::OpaqueType>(type)) 63 return true; 64 if (auto ptrType = llvm::dyn_cast<emitc::PointerType>(type)) 65 return isSupportedEmitCType(ptrType.getPointee()); 66 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(type)) { 67 auto elemType = arrayType.getElementType(); 68 return !llvm::isa<emitc::ArrayType>(elemType) && 69 isSupportedEmitCType(elemType); 70 } 71 if (type.isIndex() || emitc::isPointerWideType(type)) 72 return true; 73 if (llvm::isa<IntegerType>(type)) 74 return isSupportedIntegerType(type); 75 if (llvm::isa<FloatType>(type)) 76 return isSupportedFloatType(type); 77 if (auto tensorType = llvm::dyn_cast<TensorType>(type)) { 78 if (!tensorType.hasStaticShape()) { 79 return false; 80 } 81 auto elemType = tensorType.getElementType(); 82 if (llvm::isa<emitc::ArrayType>(elemType)) { 83 return false; 84 } 85 return isSupportedEmitCType(elemType); 86 } 87 if (auto tupleType = llvm::dyn_cast<TupleType>(type)) { 88 return llvm::all_of(tupleType.getTypes(), [](Type type) { 89 return !llvm::isa<emitc::ArrayType>(type) && isSupportedEmitCType(type); 90 }); 91 } 92 return false; 93 } 94 95 bool mlir::emitc::isSupportedIntegerType(Type type) { 96 if (auto intType = llvm::dyn_cast<IntegerType>(type)) { 97 switch (intType.getWidth()) { 98 case 1: 99 case 8: 100 case 16: 101 case 32: 102 case 64: 103 return true; 104 default: 105 return false; 106 } 107 } 108 return false; 109 } 110 111 bool mlir::emitc::isIntegerIndexOrOpaqueType(Type type) { 112 return llvm::isa<IndexType, emitc::OpaqueType>(type) || 113 isSupportedIntegerType(type) || isPointerWideType(type); 114 } 115 116 bool mlir::emitc::isSupportedFloatType(Type type) { 117 if (auto floatType = llvm::dyn_cast<FloatType>(type)) { 118 switch (floatType.getWidth()) { 119 case 16: { 120 if (llvm::isa<Float16Type, BFloat16Type>(type)) 121 return true; 122 return false; 123 } 124 case 32: 125 case 64: 126 return true; 127 default: 128 return false; 129 } 130 } 131 return false; 132 } 133 134 bool mlir::emitc::isPointerWideType(Type type) { 135 return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>( 136 type); 137 } 138 139 /// Check that the type of the initial value is compatible with the operations 140 /// result type. 141 static LogicalResult verifyInitializationAttribute(Operation *op, 142 Attribute value) { 143 assert(op->getNumResults() == 1 && "operation must have 1 result"); 144 145 if (llvm::isa<emitc::OpaqueAttr>(value)) 146 return success(); 147 148 if (llvm::isa<StringAttr>(value)) 149 return op->emitOpError() 150 << "string attributes are not supported, use #emitc.opaque instead"; 151 152 Type resultType = op->getResult(0).getType(); 153 if (auto lType = dyn_cast<LValueType>(resultType)) 154 resultType = lType.getValueType(); 155 Type attrType = cast<TypedAttr>(value).getType(); 156 157 if (isPointerWideType(resultType) && attrType.isIndex()) 158 return success(); 159 160 if (resultType != attrType) 161 return op->emitOpError() 162 << "requires attribute to either be an #emitc.opaque attribute or " 163 "it's type (" 164 << attrType << ") to match the op's result type (" << resultType 165 << ")"; 166 167 return success(); 168 } 169 170 //===----------------------------------------------------------------------===// 171 // AddOp 172 //===----------------------------------------------------------------------===// 173 174 LogicalResult AddOp::verify() { 175 Type lhsType = getLhs().getType(); 176 Type rhsType = getRhs().getType(); 177 178 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType)) 179 return emitOpError("requires that at most one operand is a pointer"); 180 181 if ((isa<emitc::PointerType>(lhsType) && 182 !isa<IntegerType, emitc::OpaqueType>(rhsType)) || 183 (isa<emitc::PointerType>(rhsType) && 184 !isa<IntegerType, emitc::OpaqueType>(lhsType))) 185 return emitOpError("requires that one operand is an integer or of opaque " 186 "type if the other is a pointer"); 187 188 return success(); 189 } 190 191 //===----------------------------------------------------------------------===// 192 // ApplyOp 193 //===----------------------------------------------------------------------===// 194 195 LogicalResult ApplyOp::verify() { 196 StringRef applicableOperatorStr = getApplicableOperator(); 197 198 // Applicable operator must not be empty. 199 if (applicableOperatorStr.empty()) 200 return emitOpError("applicable operator must not be empty"); 201 202 // Only `*` and `&` are supported. 203 if (applicableOperatorStr != "&" && applicableOperatorStr != "*") 204 return emitOpError("applicable operator is illegal"); 205 206 Type operandType = getOperand().getType(); 207 Type resultType = getResult().getType(); 208 if (applicableOperatorStr == "&") { 209 if (!llvm::isa<emitc::LValueType>(operandType)) 210 return emitOpError("operand type must be an lvalue when applying `&`"); 211 if (!llvm::isa<emitc::PointerType>(resultType)) 212 return emitOpError("result type must be a pointer when applying `&`"); 213 } else { 214 if (!llvm::isa<emitc::PointerType>(operandType)) 215 return emitOpError("operand type must be a pointer when applying `*`"); 216 } 217 218 return success(); 219 } 220 221 //===----------------------------------------------------------------------===// 222 // AssignOp 223 //===----------------------------------------------------------------------===// 224 225 /// The assign op requires that the assigned value's type matches the 226 /// assigned-to variable type. 227 LogicalResult emitc::AssignOp::verify() { 228 TypedValue<emitc::LValueType> variable = getVar(); 229 230 if (!variable.getDefiningOp()) 231 return emitOpError() << "cannot assign to block argument"; 232 233 Type valueType = getValue().getType(); 234 Type variableType = variable.getType().getValueType(); 235 if (variableType != valueType) 236 return emitOpError() << "requires value's type (" << valueType 237 << ") to match variable's type (" << variableType 238 << ")\n variable: " << variable 239 << "\n value: " << getValue() << "\n"; 240 return success(); 241 } 242 243 //===----------------------------------------------------------------------===// 244 // CastOp 245 //===----------------------------------------------------------------------===// 246 247 bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) { 248 Type input = inputs.front(), output = outputs.front(); 249 250 return ( 251 (emitc::isIntegerIndexOrOpaqueType(input) || 252 emitc::isSupportedFloatType(input) || isa<emitc::PointerType>(input)) && 253 (emitc::isIntegerIndexOrOpaqueType(output) || 254 emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output))); 255 } 256 257 //===----------------------------------------------------------------------===// 258 // CallOpaqueOp 259 //===----------------------------------------------------------------------===// 260 261 LogicalResult emitc::CallOpaqueOp::verify() { 262 // Callee must not be empty. 263 if (getCallee().empty()) 264 return emitOpError("callee must not be empty"); 265 266 if (std::optional<ArrayAttr> argsAttr = getArgs()) { 267 for (Attribute arg : *argsAttr) { 268 auto intAttr = llvm::dyn_cast<IntegerAttr>(arg); 269 if (intAttr && llvm::isa<IndexType>(intAttr.getType())) { 270 int64_t index = intAttr.getInt(); 271 // Args with elements of type index must be in range 272 // [0..operands.size). 273 if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands()))) 274 return emitOpError("index argument is out of range"); 275 276 // Args with elements of type ArrayAttr must have a type. 277 } else if (llvm::isa<ArrayAttr>( 278 arg) /*&& llvm::isa<NoneType>(arg.getType())*/) { 279 // FIXME: Array attributes never have types 280 return emitOpError("array argument has no type"); 281 } 282 } 283 } 284 285 if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) { 286 for (Attribute tArg : *templateArgsAttr) { 287 if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg)) 288 return emitOpError("template argument has invalid type"); 289 } 290 } 291 292 if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) { 293 return emitOpError() << "cannot return array type"; 294 } 295 296 return success(); 297 } 298 299 //===----------------------------------------------------------------------===// 300 // ConstantOp 301 //===----------------------------------------------------------------------===// 302 303 LogicalResult emitc::ConstantOp::verify() { 304 Attribute value = getValueAttr(); 305 if (failed(verifyInitializationAttribute(getOperation(), value))) 306 return failure(); 307 if (auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) { 308 if (opaqueValue.getValue().empty()) 309 return emitOpError() << "value must not be empty"; 310 } 311 return success(); 312 } 313 314 OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); } 315 316 //===----------------------------------------------------------------------===// 317 // ExpressionOp 318 //===----------------------------------------------------------------------===// 319 320 Operation *ExpressionOp::getRootOp() { 321 auto yieldOp = cast<YieldOp>(getBody()->getTerminator()); 322 Value yieldedValue = yieldOp.getResult(); 323 Operation *rootOp = yieldedValue.getDefiningOp(); 324 assert(rootOp && "Yielded value not defined within expression"); 325 return rootOp; 326 } 327 328 LogicalResult ExpressionOp::verify() { 329 Type resultType = getResult().getType(); 330 Region ®ion = getRegion(); 331 332 Block &body = region.front(); 333 334 if (!body.mightHaveTerminator()) 335 return emitOpError("must yield a value at termination"); 336 337 auto yield = cast<YieldOp>(body.getTerminator()); 338 Value yieldResult = yield.getResult(); 339 340 if (!yieldResult) 341 return emitOpError("must yield a value at termination"); 342 343 Type yieldType = yieldResult.getType(); 344 345 if (resultType != yieldType) 346 return emitOpError("requires yielded type to match return type"); 347 348 for (Operation &op : region.front().without_terminator()) { 349 if (!op.hasTrait<OpTrait::emitc::CExpression>()) 350 return emitOpError("contains an unsupported operation"); 351 if (op.getNumResults() != 1) 352 return emitOpError("requires exactly one result for each operation"); 353 if (!op.getResult(0).hasOneUse()) 354 return emitOpError("requires exactly one use for each operation"); 355 } 356 357 return success(); 358 } 359 360 //===----------------------------------------------------------------------===// 361 // ForOp 362 //===----------------------------------------------------------------------===// 363 364 void ForOp::build(OpBuilder &builder, OperationState &result, Value lb, 365 Value ub, Value step, BodyBuilderFn bodyBuilder) { 366 OpBuilder::InsertionGuard g(builder); 367 result.addOperands({lb, ub, step}); 368 Type t = lb.getType(); 369 Region *bodyRegion = result.addRegion(); 370 Block *bodyBlock = builder.createBlock(bodyRegion); 371 bodyBlock->addArgument(t, result.location); 372 373 // Create the default terminator if the builder is not provided. 374 if (!bodyBuilder) { 375 ForOp::ensureTerminator(*bodyRegion, builder, result.location); 376 } else { 377 OpBuilder::InsertionGuard guard(builder); 378 builder.setInsertionPointToStart(bodyBlock); 379 bodyBuilder(builder, result.location, bodyBlock->getArgument(0)); 380 } 381 } 382 383 void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {} 384 385 ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) { 386 Builder &builder = parser.getBuilder(); 387 Type type; 388 389 OpAsmParser::Argument inductionVariable; 390 OpAsmParser::UnresolvedOperand lb, ub, step; 391 392 // Parse the induction variable followed by '='. 393 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() || 394 // Parse loop bounds. 395 parser.parseOperand(lb) || parser.parseKeyword("to") || 396 parser.parseOperand(ub) || parser.parseKeyword("step") || 397 parser.parseOperand(step)) 398 return failure(); 399 400 // Parse the optional initial iteration arguments. 401 SmallVector<OpAsmParser::Argument, 4> regionArgs; 402 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands; 403 regionArgs.push_back(inductionVariable); 404 405 // Parse optional type, else assume Index. 406 if (parser.parseOptionalColon()) 407 type = builder.getIndexType(); 408 else if (parser.parseType(type)) 409 return failure(); 410 411 // Resolve input operands. 412 regionArgs.front().type = type; 413 if (parser.resolveOperand(lb, type, result.operands) || 414 parser.resolveOperand(ub, type, result.operands) || 415 parser.resolveOperand(step, type, result.operands)) 416 return failure(); 417 418 // Parse the body region. 419 Region *body = result.addRegion(); 420 if (parser.parseRegion(*body, regionArgs)) 421 return failure(); 422 423 ForOp::ensureTerminator(*body, builder, result.location); 424 425 // Parse the optional attribute list. 426 if (parser.parseOptionalAttrDict(result.attributes)) 427 return failure(); 428 429 return success(); 430 } 431 432 void ForOp::print(OpAsmPrinter &p) { 433 p << " " << getInductionVar() << " = " << getLowerBound() << " to " 434 << getUpperBound() << " step " << getStep(); 435 436 p << ' '; 437 if (Type t = getInductionVar().getType(); !t.isIndex()) 438 p << " : " << t << ' '; 439 p.printRegion(getRegion(), 440 /*printEntryBlockArgs=*/false, 441 /*printBlockTerminators=*/false); 442 p.printOptionalAttrDict((*this)->getAttrs()); 443 } 444 445 LogicalResult ForOp::verifyRegions() { 446 // Check that the body defines as single block argument for the induction 447 // variable. 448 if (getInductionVar().getType() != getLowerBound().getType()) 449 return emitOpError( 450 "expected induction variable to be same type as bounds and step"); 451 452 return success(); 453 } 454 455 //===----------------------------------------------------------------------===// 456 // CallOp 457 //===----------------------------------------------------------------------===// 458 459 LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) { 460 // Check that the callee attribute was specified. 461 auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee"); 462 if (!fnAttr) 463 return emitOpError("requires a 'callee' symbol reference attribute"); 464 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr); 465 if (!fn) 466 return emitOpError() << "'" << fnAttr.getValue() 467 << "' does not reference a valid function"; 468 469 // Verify that the operand and result types match the callee. 470 auto fnType = fn.getFunctionType(); 471 if (fnType.getNumInputs() != getNumOperands()) 472 return emitOpError("incorrect number of operands for callee"); 473 474 for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i) 475 if (getOperand(i).getType() != fnType.getInput(i)) 476 return emitOpError("operand type mismatch: expected operand type ") 477 << fnType.getInput(i) << ", but provided " 478 << getOperand(i).getType() << " for operand number " << i; 479 480 if (fnType.getNumResults() != getNumResults()) 481 return emitOpError("incorrect number of results for callee"); 482 483 for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i) 484 if (getResult(i).getType() != fnType.getResult(i)) { 485 auto diag = emitOpError("result type mismatch at index ") << i; 486 diag.attachNote() << " op result types: " << getResultTypes(); 487 diag.attachNote() << "function result types: " << fnType.getResults(); 488 return diag; 489 } 490 491 return success(); 492 } 493 494 FunctionType CallOp::getCalleeType() { 495 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes()); 496 } 497 498 //===----------------------------------------------------------------------===// 499 // DeclareFuncOp 500 //===----------------------------------------------------------------------===// 501 502 LogicalResult 503 DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) { 504 // Check that the sym_name attribute was specified. 505 auto fnAttr = getSymNameAttr(); 506 if (!fnAttr) 507 return emitOpError("requires a 'sym_name' symbol reference attribute"); 508 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr); 509 if (!fn) 510 return emitOpError() << "'" << fnAttr.getValue() 511 << "' does not reference a valid function"; 512 513 return success(); 514 } 515 516 //===----------------------------------------------------------------------===// 517 // FuncOp 518 //===----------------------------------------------------------------------===// 519 520 void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name, 521 FunctionType type, ArrayRef<NamedAttribute> attrs, 522 ArrayRef<DictionaryAttr> argAttrs) { 523 state.addAttribute(SymbolTable::getSymbolAttrName(), 524 builder.getStringAttr(name)); 525 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type)); 526 state.attributes.append(attrs.begin(), attrs.end()); 527 state.addRegion(); 528 529 if (argAttrs.empty()) 530 return; 531 assert(type.getNumInputs() == argAttrs.size()); 532 function_interface_impl::addArgAndResultAttrs( 533 builder, state, argAttrs, /*resultAttrs=*/std::nullopt, 534 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name)); 535 } 536 537 ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) { 538 auto buildFuncType = 539 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results, 540 function_interface_impl::VariadicFlag, 541 std::string &) { return builder.getFunctionType(argTypes, results); }; 542 543 return function_interface_impl::parseFunctionOp( 544 parser, result, /*allowVariadic=*/false, 545 getFunctionTypeAttrName(result.name), buildFuncType, 546 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name)); 547 } 548 549 void FuncOp::print(OpAsmPrinter &p) { 550 function_interface_impl::printFunctionOp( 551 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(), 552 getArgAttrsAttrName(), getResAttrsAttrName()); 553 } 554 555 LogicalResult FuncOp::verify() { 556 if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) { 557 return emitOpError("cannot have lvalue type as argument"); 558 } 559 560 if (getNumResults() > 1) 561 return emitOpError("requires zero or exactly one result, but has ") 562 << getNumResults(); 563 564 if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0])) 565 return emitOpError("cannot return array type"); 566 567 return success(); 568 } 569 570 //===----------------------------------------------------------------------===// 571 // ReturnOp 572 //===----------------------------------------------------------------------===// 573 574 LogicalResult ReturnOp::verify() { 575 auto function = cast<FuncOp>((*this)->getParentOp()); 576 577 // The operand number and types must match the function signature. 578 if (getNumOperands() != function.getNumResults()) 579 return emitOpError("has ") 580 << getNumOperands() << " operands, but enclosing function (@" 581 << function.getName() << ") returns " << function.getNumResults(); 582 583 if (function.getNumResults() == 1) 584 if (getOperand().getType() != function.getResultTypes()[0]) 585 return emitError() << "type of the return operand (" 586 << getOperand().getType() 587 << ") doesn't match function result type (" 588 << function.getResultTypes()[0] << ")" 589 << " in function @" << function.getName(); 590 return success(); 591 } 592 593 //===----------------------------------------------------------------------===// 594 // IfOp 595 //===----------------------------------------------------------------------===// 596 597 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond, 598 bool addThenBlock, bool addElseBlock) { 599 assert((!addElseBlock || addThenBlock) && 600 "must not create else block w/o then block"); 601 result.addOperands(cond); 602 603 // Add regions and blocks. 604 OpBuilder::InsertionGuard guard(builder); 605 Region *thenRegion = result.addRegion(); 606 if (addThenBlock) 607 builder.createBlock(thenRegion); 608 Region *elseRegion = result.addRegion(); 609 if (addElseBlock) 610 builder.createBlock(elseRegion); 611 } 612 613 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond, 614 bool withElseRegion) { 615 result.addOperands(cond); 616 617 // Build then region. 618 OpBuilder::InsertionGuard guard(builder); 619 Region *thenRegion = result.addRegion(); 620 builder.createBlock(thenRegion); 621 622 // Build else region. 623 Region *elseRegion = result.addRegion(); 624 if (withElseRegion) { 625 builder.createBlock(elseRegion); 626 } 627 } 628 629 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond, 630 function_ref<void(OpBuilder &, Location)> thenBuilder, 631 function_ref<void(OpBuilder &, Location)> elseBuilder) { 632 assert(thenBuilder && "the builder callback for 'then' must be present"); 633 result.addOperands(cond); 634 635 // Build then region. 636 OpBuilder::InsertionGuard guard(builder); 637 Region *thenRegion = result.addRegion(); 638 builder.createBlock(thenRegion); 639 thenBuilder(builder, result.location); 640 641 // Build else region. 642 Region *elseRegion = result.addRegion(); 643 if (elseBuilder) { 644 builder.createBlock(elseRegion); 645 elseBuilder(builder, result.location); 646 } 647 } 648 649 ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) { 650 // Create the regions for 'then'. 651 result.regions.reserve(2); 652 Region *thenRegion = result.addRegion(); 653 Region *elseRegion = result.addRegion(); 654 655 Builder &builder = parser.getBuilder(); 656 OpAsmParser::UnresolvedOperand cond; 657 Type i1Type = builder.getIntegerType(1); 658 if (parser.parseOperand(cond) || 659 parser.resolveOperand(cond, i1Type, result.operands)) 660 return failure(); 661 // Parse the 'then' region. 662 if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{})) 663 return failure(); 664 IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location); 665 666 // If we find an 'else' keyword then parse the 'else' region. 667 if (!parser.parseOptionalKeyword("else")) { 668 if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{})) 669 return failure(); 670 IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location); 671 } 672 673 // Parse the optional attribute list. 674 if (parser.parseOptionalAttrDict(result.attributes)) 675 return failure(); 676 return success(); 677 } 678 679 void IfOp::print(OpAsmPrinter &p) { 680 bool printBlockTerminators = false; 681 682 p << " " << getCondition(); 683 p << ' '; 684 p.printRegion(getThenRegion(), 685 /*printEntryBlockArgs=*/false, 686 /*printBlockTerminators=*/printBlockTerminators); 687 688 // Print the 'else' regions if it exists and has a block. 689 Region &elseRegion = getElseRegion(); 690 if (!elseRegion.empty()) { 691 p << " else "; 692 p.printRegion(elseRegion, 693 /*printEntryBlockArgs=*/false, 694 /*printBlockTerminators=*/printBlockTerminators); 695 } 696 697 p.printOptionalAttrDict((*this)->getAttrs()); 698 } 699 700 /// Given the region at `index`, or the parent operation if `index` is None, 701 /// return the successor regions. These are the regions that may be selected 702 /// during the flow of control. `operands` is a set of optional attributes that 703 /// correspond to a constant value for each operand, or null if that operand is 704 /// not a constant. 705 void IfOp::getSuccessorRegions(RegionBranchPoint point, 706 SmallVectorImpl<RegionSuccessor> ®ions) { 707 // The `then` and the `else` region branch back to the parent operation. 708 if (!point.isParent()) { 709 regions.push_back(RegionSuccessor()); 710 return; 711 } 712 713 regions.push_back(RegionSuccessor(&getThenRegion())); 714 715 // Don't consider the else region if it is empty. 716 Region *elseRegion = &this->getElseRegion(); 717 if (elseRegion->empty()) 718 regions.push_back(RegionSuccessor()); 719 else 720 regions.push_back(RegionSuccessor(elseRegion)); 721 } 722 723 void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands, 724 SmallVectorImpl<RegionSuccessor> ®ions) { 725 FoldAdaptor adaptor(operands, *this); 726 auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition()); 727 if (!boolAttr || boolAttr.getValue()) 728 regions.emplace_back(&getThenRegion()); 729 730 // If the else region is empty, execution continues after the parent op. 731 if (!boolAttr || !boolAttr.getValue()) { 732 if (!getElseRegion().empty()) 733 regions.emplace_back(&getElseRegion()); 734 else 735 regions.emplace_back(); 736 } 737 } 738 739 void IfOp::getRegionInvocationBounds( 740 ArrayRef<Attribute> operands, 741 SmallVectorImpl<InvocationBounds> &invocationBounds) { 742 if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) { 743 // If the condition is known, then one region is known to be executed once 744 // and the other zero times. 745 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0); 746 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1); 747 } else { 748 // Non-constant condition. Each region may be executed 0 or 1 times. 749 invocationBounds.assign(2, {0, 1}); 750 } 751 } 752 753 //===----------------------------------------------------------------------===// 754 // IncludeOp 755 //===----------------------------------------------------------------------===// 756 757 void IncludeOp::print(OpAsmPrinter &p) { 758 bool standardInclude = getIsStandardInclude(); 759 760 p << " "; 761 if (standardInclude) 762 p << "<"; 763 p << "\"" << getInclude() << "\""; 764 if (standardInclude) 765 p << ">"; 766 } 767 768 ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) { 769 bool standardInclude = !parser.parseOptionalLess(); 770 771 StringAttr include; 772 OptionalParseResult includeParseResult = 773 parser.parseOptionalAttribute(include, "include", result.attributes); 774 if (!includeParseResult.has_value()) 775 return parser.emitError(parser.getNameLoc()) << "expected string attribute"; 776 777 if (standardInclude && parser.parseOptionalGreater()) 778 return parser.emitError(parser.getNameLoc()) 779 << "expected trailing '>' for standard include"; 780 781 if (standardInclude) 782 result.addAttribute("is_standard_include", 783 UnitAttr::get(parser.getContext())); 784 785 return success(); 786 } 787 788 //===----------------------------------------------------------------------===// 789 // LiteralOp 790 //===----------------------------------------------------------------------===// 791 792 /// The literal op requires a non-empty value. 793 LogicalResult emitc::LiteralOp::verify() { 794 if (getValue().empty()) 795 return emitOpError() << "value must not be empty"; 796 return success(); 797 } 798 //===----------------------------------------------------------------------===// 799 // SubOp 800 //===----------------------------------------------------------------------===// 801 802 LogicalResult SubOp::verify() { 803 Type lhsType = getLhs().getType(); 804 Type rhsType = getRhs().getType(); 805 Type resultType = getResult().getType(); 806 807 if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType)) 808 return emitOpError("rhs can only be a pointer if lhs is a pointer"); 809 810 if (isa<emitc::PointerType>(lhsType) && 811 !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType)) 812 return emitOpError("requires that rhs is an integer, pointer or of opaque " 813 "type if lhs is a pointer"); 814 815 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) && 816 !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType)) 817 return emitOpError("requires that the result is an integer, ptrdiff_t or " 818 "of opaque type if lhs and rhs are pointers"); 819 return success(); 820 } 821 822 //===----------------------------------------------------------------------===// 823 // VariableOp 824 //===----------------------------------------------------------------------===// 825 826 LogicalResult emitc::VariableOp::verify() { 827 return verifyInitializationAttribute(getOperation(), getValueAttr()); 828 } 829 830 //===----------------------------------------------------------------------===// 831 // YieldOp 832 //===----------------------------------------------------------------------===// 833 834 LogicalResult emitc::YieldOp::verify() { 835 Value result = getResult(); 836 Operation *containingOp = getOperation()->getParentOp(); 837 838 if (result && containingOp->getNumResults() != 1) 839 return emitOpError() << "yields a value not returned by parent"; 840 841 if (!result && containingOp->getNumResults() != 0) 842 return emitOpError() << "does not yield a value to be returned by parent"; 843 844 return success(); 845 } 846 847 //===----------------------------------------------------------------------===// 848 // SubscriptOp 849 //===----------------------------------------------------------------------===// 850 851 LogicalResult emitc::SubscriptOp::verify() { 852 // Checks for array operand. 853 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) { 854 // Check number of indices. 855 if (getIndices().size() != (size_t)arrayType.getRank()) { 856 return emitOpError() << "on array operand requires number of indices (" 857 << getIndices().size() 858 << ") to match the rank of the array type (" 859 << arrayType.getRank() << ")"; 860 } 861 // Check types of index operands. 862 for (unsigned i = 0, e = getIndices().size(); i != e; ++i) { 863 Type type = getIndices()[i].getType(); 864 if (!isIntegerIndexOrOpaqueType(type)) { 865 return emitOpError() << "on array operand requires index operand " << i 866 << " to be integer-like, but got " << type; 867 } 868 } 869 // Check element type. 870 Type elementType = arrayType.getElementType(); 871 Type resultType = getType().getValueType(); 872 if (elementType != resultType) { 873 return emitOpError() << "on array operand requires element type (" 874 << elementType << ") and result type (" << resultType 875 << ") to match"; 876 } 877 return success(); 878 } 879 880 // Checks for pointer operand. 881 if (auto pointerType = 882 llvm::dyn_cast<emitc::PointerType>(getValue().getType())) { 883 // Check number of indices. 884 if (getIndices().size() != 1) { 885 return emitOpError() 886 << "on pointer operand requires one index operand, but got " 887 << getIndices().size(); 888 } 889 // Check types of index operand. 890 Type type = getIndices()[0].getType(); 891 if (!isIntegerIndexOrOpaqueType(type)) { 892 return emitOpError() << "on pointer operand requires index operand to be " 893 "integer-like, but got " 894 << type; 895 } 896 // Check pointee type. 897 Type pointeeType = pointerType.getPointee(); 898 Type resultType = getType().getValueType(); 899 if (pointeeType != resultType) { 900 return emitOpError() << "on pointer operand requires pointee type (" 901 << pointeeType << ") and result type (" << resultType 902 << ") to match"; 903 } 904 return success(); 905 } 906 907 // The operand has opaque type, so we can't assume anything about the number 908 // or types of index operands. 909 return success(); 910 } 911 912 //===----------------------------------------------------------------------===// 913 // EmitC Enums 914 //===----------------------------------------------------------------------===// 915 916 #include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc" 917 918 //===----------------------------------------------------------------------===// 919 // EmitC Attributes 920 //===----------------------------------------------------------------------===// 921 922 #define GET_ATTRDEF_CLASSES 923 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc" 924 925 //===----------------------------------------------------------------------===// 926 // EmitC Types 927 //===----------------------------------------------------------------------===// 928 929 #define GET_TYPEDEF_CLASSES 930 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc" 931 932 //===----------------------------------------------------------------------===// 933 // ArrayType 934 //===----------------------------------------------------------------------===// 935 936 Type emitc::ArrayType::parse(AsmParser &parser) { 937 if (parser.parseLess()) 938 return Type(); 939 940 SmallVector<int64_t, 4> dimensions; 941 if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false, 942 /*withTrailingX=*/true)) 943 return Type(); 944 // Parse the element type. 945 auto typeLoc = parser.getCurrentLocation(); 946 Type elementType; 947 if (parser.parseType(elementType)) 948 return Type(); 949 950 // Check that array is formed from allowed types. 951 if (!isValidElementType(elementType)) 952 return parser.emitError(typeLoc, "invalid array element type"), Type(); 953 if (parser.parseGreater()) 954 return Type(); 955 return parser.getChecked<ArrayType>(dimensions, elementType); 956 } 957 958 void emitc::ArrayType::print(AsmPrinter &printer) const { 959 printer << "<"; 960 for (int64_t dim : getShape()) { 961 printer << dim << 'x'; 962 } 963 printer.printType(getElementType()); 964 printer << ">"; 965 } 966 967 LogicalResult emitc::ArrayType::verify( 968 ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, 969 ::llvm::ArrayRef<int64_t> shape, Type elementType) { 970 if (shape.empty()) 971 return emitError() << "shape must not be empty"; 972 973 for (int64_t dim : shape) { 974 if (dim < 0) 975 return emitError() << "dimensions must have non-negative size"; 976 } 977 978 if (!elementType) 979 return emitError() << "element type must not be none"; 980 981 if (!isValidElementType(elementType)) 982 return emitError() << "invalid array element type"; 983 984 return success(); 985 } 986 987 emitc::ArrayType 988 emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape, 989 Type elementType) const { 990 if (!shape) 991 return emitc::ArrayType::get(getShape(), elementType); 992 return emitc::ArrayType::get(*shape, elementType); 993 } 994 995 //===----------------------------------------------------------------------===// 996 // LValueType 997 //===----------------------------------------------------------------------===// 998 999 LogicalResult mlir::emitc::LValueType::verify( 1000 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, 1001 mlir::Type value) { 1002 // Check that the wrapped type is valid. This especially forbids nested lvalue 1003 // types. 1004 if (!isSupportedEmitCType(value)) 1005 return emitError() 1006 << "!emitc.lvalue must wrap supported emitc type, but got " << value; 1007 1008 if (llvm::isa<emitc::ArrayType>(value)) 1009 return emitError() << "!emitc.lvalue cannot wrap !emitc.array type"; 1010 1011 return success(); 1012 } 1013 1014 //===----------------------------------------------------------------------===// 1015 // OpaqueType 1016 //===----------------------------------------------------------------------===// 1017 1018 LogicalResult mlir::emitc::OpaqueType::verify( 1019 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, 1020 llvm::StringRef value) { 1021 if (value.empty()) { 1022 return emitError() << "expected non empty string in !emitc.opaque type"; 1023 } 1024 if (value.back() == '*') { 1025 return emitError() << "pointer not allowed as outer type with " 1026 "!emitc.opaque, use !emitc.ptr instead"; 1027 } 1028 return success(); 1029 } 1030 1031 //===----------------------------------------------------------------------===// 1032 // PointerType 1033 //===----------------------------------------------------------------------===// 1034 1035 LogicalResult mlir::emitc::PointerType::verify( 1036 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, Type value) { 1037 if (llvm::isa<emitc::LValueType>(value)) 1038 return emitError() << "pointers to lvalues are not allowed"; 1039 1040 return success(); 1041 } 1042 1043 //===----------------------------------------------------------------------===// 1044 // GlobalOp 1045 //===----------------------------------------------------------------------===// 1046 static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, 1047 TypeAttr type, 1048 Attribute initialValue) { 1049 p << type; 1050 if (initialValue) { 1051 p << " = "; 1052 p.printAttributeWithoutType(initialValue); 1053 } 1054 } 1055 1056 static Type getInitializerTypeForGlobal(Type type) { 1057 if (auto array = llvm::dyn_cast<ArrayType>(type)) 1058 return RankedTensorType::get(array.getShape(), array.getElementType()); 1059 return type; 1060 } 1061 1062 static ParseResult 1063 parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, 1064 Attribute &initialValue) { 1065 Type type; 1066 if (parser.parseType(type)) 1067 return failure(); 1068 1069 typeAttr = TypeAttr::get(type); 1070 1071 if (parser.parseOptionalEqual()) 1072 return success(); 1073 1074 if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type))) 1075 return failure(); 1076 1077 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>( 1078 initialValue)) 1079 return parser.emitError(parser.getNameLoc()) 1080 << "initial value should be a integer, float, elements or opaque " 1081 "attribute"; 1082 return success(); 1083 } 1084 1085 LogicalResult GlobalOp::verify() { 1086 if (!isSupportedEmitCType(getType())) { 1087 return emitOpError("expected valid emitc type"); 1088 } 1089 if (getInitialValue().has_value()) { 1090 Attribute initValue = getInitialValue().value(); 1091 // Check that the type of the initial value is compatible with the type of 1092 // the global variable. 1093 if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) { 1094 auto arrayType = llvm::dyn_cast<ArrayType>(getType()); 1095 if (!arrayType) 1096 return emitOpError("expected array type, but got ") << getType(); 1097 1098 Type initType = elementsAttr.getType(); 1099 Type tensorType = getInitializerTypeForGlobal(getType()); 1100 if (initType != tensorType) { 1101 return emitOpError("initial value expected to be of type ") 1102 << getType() << ", but was of type " << initType; 1103 } 1104 } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) { 1105 if (intAttr.getType() != getType()) { 1106 return emitOpError("initial value expected to be of type ") 1107 << getType() << ", but was of type " << intAttr.getType(); 1108 } 1109 } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) { 1110 if (floatAttr.getType() != getType()) { 1111 return emitOpError("initial value expected to be of type ") 1112 << getType() << ", but was of type " << floatAttr.getType(); 1113 } 1114 } else if (!isa<emitc::OpaqueAttr>(initValue)) { 1115 return emitOpError("initial value should be a integer, float, elements " 1116 "or opaque attribute, but got ") 1117 << initValue; 1118 } 1119 } 1120 if (getStaticSpecifier() && getExternSpecifier()) { 1121 return emitOpError("cannot have both static and extern specifiers"); 1122 } 1123 return success(); 1124 } 1125 1126 //===----------------------------------------------------------------------===// 1127 // GetGlobalOp 1128 //===----------------------------------------------------------------------===// 1129 1130 LogicalResult 1131 GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { 1132 // Verify that the type matches the type of the global variable. 1133 auto global = 1134 symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr()); 1135 if (!global) 1136 return emitOpError("'") 1137 << getName() << "' does not reference a valid emitc.global"; 1138 1139 Type resultType = getResult().getType(); 1140 Type globalType = global.getType(); 1141 1142 // global has array type 1143 if (llvm::isa<ArrayType>(globalType)) { 1144 if (globalType != resultType) 1145 return emitOpError("on array type expects result type ") 1146 << resultType << " to match type " << globalType 1147 << " of the global @" << getName(); 1148 return success(); 1149 } 1150 1151 // global has non-array type 1152 auto lvalueType = dyn_cast<LValueType>(resultType); 1153 if (!lvalueType || lvalueType.getValueType() != globalType) 1154 return emitOpError("on non-array type expects result inner type ") 1155 << lvalueType.getValueType() << " to match type " << globalType 1156 << " of the global @" << getName(); 1157 return success(); 1158 } 1159 1160 //===----------------------------------------------------------------------===// 1161 // SwitchOp 1162 //===----------------------------------------------------------------------===// 1163 1164 /// Parse the case regions and values. 1165 static ParseResult 1166 parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, 1167 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) { 1168 SmallVector<int64_t> caseValues; 1169 while (succeeded(parser.parseOptionalKeyword("case"))) { 1170 int64_t value; 1171 Region ®ion = *caseRegions.emplace_back(std::make_unique<Region>()); 1172 if (parser.parseInteger(value) || 1173 parser.parseRegion(region, /*arguments=*/{})) 1174 return failure(); 1175 caseValues.push_back(value); 1176 } 1177 cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues); 1178 return success(); 1179 } 1180 1181 /// Print the case regions and values. 1182 static void printSwitchCases(OpAsmPrinter &p, Operation *op, 1183 DenseI64ArrayAttr cases, RegionRange caseRegions) { 1184 for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) { 1185 p.printNewline(); 1186 p << "case " << value << ' '; 1187 p.printRegion(*region, /*printEntryBlockArgs=*/false); 1188 } 1189 } 1190 1191 static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, 1192 const Twine &name) { 1193 auto yield = dyn_cast<emitc::YieldOp>(region.front().back()); 1194 if (!yield) 1195 return op.emitOpError("expected region to end with emitc.yield, but got ") 1196 << region.front().back().getName(); 1197 1198 if (yield.getNumOperands() != 0) { 1199 return (op.emitOpError("expected each region to return ") 1200 << "0 values, but " << name << " returns " 1201 << yield.getNumOperands()) 1202 .attachNote(yield.getLoc()) 1203 << "see yield operation here"; 1204 } 1205 1206 return success(); 1207 } 1208 1209 LogicalResult emitc::SwitchOp::verify() { 1210 if (!isIntegerIndexOrOpaqueType(getArg().getType())) 1211 return emitOpError("unsupported type ") << getArg().getType(); 1212 1213 if (getCases().size() != getCaseRegions().size()) { 1214 return emitOpError("has ") 1215 << getCaseRegions().size() << " case regions but " 1216 << getCases().size() << " case values"; 1217 } 1218 1219 DenseSet<int64_t> valueSet; 1220 for (int64_t value : getCases()) 1221 if (!valueSet.insert(value).second) 1222 return emitOpError("has duplicate case value: ") << value; 1223 1224 if (failed(verifyRegion(*this, getDefaultRegion(), "default region"))) 1225 return failure(); 1226 1227 for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions())) 1228 if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx)))) 1229 return failure(); 1230 1231 return success(); 1232 } 1233 1234 unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); } 1235 1236 Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); } 1237 1238 Block &emitc::SwitchOp::getCaseBlock(unsigned idx) { 1239 assert(idx < getNumCases() && "case index out-of-bounds"); 1240 return getCaseRegions()[idx].front(); 1241 } 1242 1243 void SwitchOp::getSuccessorRegions( 1244 RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &successors) { 1245 llvm::copy(getRegions(), std::back_inserter(successors)); 1246 } 1247 1248 void SwitchOp::getEntrySuccessorRegions( 1249 ArrayRef<Attribute> operands, 1250 SmallVectorImpl<RegionSuccessor> &successors) { 1251 FoldAdaptor adaptor(operands, *this); 1252 1253 // If a constant was not provided, all regions are possible successors. 1254 auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg()); 1255 if (!arg) { 1256 llvm::copy(getRegions(), std::back_inserter(successors)); 1257 return; 1258 } 1259 1260 // Otherwise, try to find a case with a matching value. If not, the 1261 // default region is the only successor. 1262 for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) { 1263 if (caseValue == arg.getInt()) { 1264 successors.emplace_back(&caseRegion); 1265 return; 1266 } 1267 } 1268 successors.emplace_back(&getDefaultRegion()); 1269 } 1270 1271 void SwitchOp::getRegionInvocationBounds( 1272 ArrayRef<Attribute> operands, SmallVectorImpl<InvocationBounds> &bounds) { 1273 auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front()); 1274 if (!operandValue) { 1275 // All regions are invoked at most once. 1276 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1)); 1277 return; 1278 } 1279 1280 unsigned liveIndex = getNumRegions() - 1; 1281 const auto *iteratorToInt = llvm::find(getCases(), operandValue.getInt()); 1282 1283 liveIndex = iteratorToInt != getCases().end() 1284 ? std::distance(getCases().begin(), iteratorToInt) 1285 : liveIndex; 1286 1287 for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum; 1288 ++regIndex) 1289 bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex); 1290 } 1291 1292 //===----------------------------------------------------------------------===// 1293 // TableGen'd op method definitions 1294 //===----------------------------------------------------------------------===// 1295 1296 #define GET_OP_CLASSES 1297 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc" 1298