xref: /llvm-project/mlir/lib/Dialect/EmitC/IR/EmitC.cpp (revision 0bd07652524ebacdee166eb609fef48c50769b09)
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 &region = 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> &regions) {
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> &regions) {
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 &region = *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 &region,
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