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