MLIR  22.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/Types.h"
17 #include "mlir/Support/LLVM.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallVector.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.
50  Attribute value, Type type,
51  Location loc) {
52  return emitc::ConstantOp::create(builder, loc, type, value);
53 }
54 
55 /// Default callback for builders of ops carrying a region. Inserts a yield
56 /// without arguments.
58  emitc::YieldOp::create(builder, loc);
59 }
60 
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 
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 
112  return llvm::isa<IndexType, emitc::OpaqueType>(type) ||
114 }
115 
117  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {
118  switch (floatType.getWidth()) {
119  case 16:
120  return llvm::isa<Float16Type, BFloat16Type>(type);
121  case 32:
122  case 64:
123  return true;
124  default:
125  return false;
126  }
127  }
128  return false;
129 }
130 
132  return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>(
133  type);
134 }
135 
137  return llvm::isa<IndexType>(type) || isPointerWideType(type) ||
139  isa<emitc::PointerType>(type);
140 }
141 
142 /// Check that the type of the initial value is compatible with the operations
143 /// result type.
144 static LogicalResult verifyInitializationAttribute(Operation *op,
145  Attribute value) {
146  assert(op->getNumResults() == 1 && "operation must have 1 result");
147 
148  if (llvm::isa<emitc::OpaqueAttr>(value))
149  return success();
150 
151  if (llvm::isa<StringAttr>(value))
152  return op->emitOpError()
153  << "string attributes are not supported, use #emitc.opaque instead";
154 
155  Type resultType = op->getResult(0).getType();
156  if (auto lType = dyn_cast<LValueType>(resultType))
157  resultType = lType.getValueType();
158  Type attrType = cast<TypedAttr>(value).getType();
159 
160  if (isPointerWideType(resultType) && attrType.isIndex())
161  return success();
162 
163  if (resultType != attrType)
164  return op->emitOpError()
165  << "requires attribute to either be an #emitc.opaque attribute or "
166  "it's type ("
167  << attrType << ") to match the op's result type (" << resultType
168  << ")";
169 
170  return success();
171 }
172 
173 /// Parse a format string and return a list of its parts.
174 /// A part is either a StringRef that has to be printed as-is, or
175 /// a Placeholder which requires printing the next operand of the VerbatimOp.
176 /// In the format string, all `{}` are replaced by Placeholders, except if the
177 /// `{` is escaped by `{{` - then it doesn't start a placeholder.
178 template <class ArgType>
179 FailureOr<SmallVector<ReplacementItem>> parseFormatString(
180  StringRef toParse, ArgType fmtArgs,
183 
184  // If there are not operands, the format string is not interpreted.
185  if (fmtArgs.empty()) {
186  items.push_back(toParse);
187  return items;
188  }
189 
190  while (!toParse.empty()) {
191  size_t idx = toParse.find('{');
192  if (idx == StringRef::npos) {
193  // No '{'
194  items.push_back(toParse);
195  break;
196  }
197  if (idx > 0) {
198  // Take all chars excluding the '{'.
199  items.push_back(toParse.take_front(idx));
200  toParse = toParse.drop_front(idx);
201  continue;
202  }
203  if (toParse.size() < 2) {
204  return emitError() << "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) {
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 ParseResult ExpressionOp::parse(OpAsmParser &parser, OperationState &result) {
388  if (parser.parseOperandList(operands))
389  return parser.emitError(parser.getCurrentLocation()) << "expected operands";
390  if (succeeded(parser.parseOptionalKeyword("noinline")))
391  result.addAttribute(ExpressionOp::getDoNotInlineAttrName(result.name),
392  parser.getBuilder().getUnitAttr());
393  Type type;
394  if (parser.parseColonType(type))
395  return parser.emitError(parser.getCurrentLocation(),
396  "expected function type");
397  auto fnType = llvm::dyn_cast<FunctionType>(type);
398  if (!fnType)
399  return parser.emitError(parser.getCurrentLocation(),
400  "expected function type");
401  if (parser.resolveOperands(operands, fnType.getInputs(),
402  parser.getCurrentLocation(), result.operands))
403  return failure();
404  if (fnType.getNumResults() != 1)
405  return parser.emitError(parser.getCurrentLocation(),
406  "expected single return type");
407  result.addTypes(fnType.getResults());
408  Region *body = result.addRegion();
410  for (auto [unresolvedOperand, operandType] :
411  llvm::zip(operands, fnType.getInputs())) {
412  OpAsmParser::Argument argInfo;
413  argInfo.ssaName = unresolvedOperand;
414  argInfo.type = operandType;
415  argsInfo.push_back(argInfo);
416  }
417  if (parser.parseRegion(*body, argsInfo, /*enableNameShadowing=*/true))
418  return failure();
419  return success();
420 }
421 
423  p << ' ';
424  p.printOperands(getDefs());
425  p << " : ";
426  p.printFunctionalType(getOperation());
427  p.shadowRegionArgs(getRegion(), getDefs());
428  p << ' ';
429  p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);
430 }
431 
432 Operation *ExpressionOp::getRootOp() {
433  auto yieldOp = cast<YieldOp>(getBody()->getTerminator());
434  Value yieldedValue = yieldOp.getResult();
435  return yieldedValue.getDefiningOp();
436 }
437 
438 LogicalResult ExpressionOp::verify() {
439  Type resultType = getResult().getType();
440  Region &region = getRegion();
441 
442  Block &body = region.front();
443 
444  if (!body.mightHaveTerminator())
445  return emitOpError("must yield a value at termination");
446 
447  auto yield = cast<YieldOp>(body.getTerminator());
448  Value yieldResult = yield.getResult();
449 
450  if (!yieldResult)
451  return emitOpError("must yield a value at termination");
452 
453  Operation *rootOp = yieldResult.getDefiningOp();
454 
455  if (!rootOp)
456  return emitOpError("yielded value has no defining op");
457 
458  if (rootOp->getParentOp() != getOperation())
459  return emitOpError("yielded value not defined within expression");
460 
461  Type yieldType = yieldResult.getType();
462 
463  if (resultType != yieldType)
464  return emitOpError("requires yielded type to match return type");
465 
466  for (Operation &op : region.front().without_terminator()) {
467  auto expressionInterface = dyn_cast<emitc::CExpressionInterface>(op);
468  if (!expressionInterface)
469  return emitOpError("contains an unsupported operation");
470  if (op.getNumResults() != 1)
471  return emitOpError("requires exactly one result for each operation");
472  Value result = op.getResult(0);
473  if (result.use_empty())
474  return emitOpError("contains an unused operation");
475  }
476 
477  // Make sure any operation with side effect is only reachable once from
478  // the root op, otherwise emission will be replicating side effects.
480  SmallVector<Operation *> worklist;
481  worklist.push_back(rootOp);
482  while (!worklist.empty()) {
483  Operation *op = worklist.back();
484  worklist.pop_back();
485  if (visited.contains(op)) {
486  if (cast<CExpressionInterface>(op).hasSideEffects())
487  return emitOpError(
488  "requires exactly one use for operations with side effects");
489  }
490  visited.insert(op);
491  for (Value operand : op->getOperands())
492  if (Operation *def = operand.getDefiningOp()) {
493  worklist.push_back(def);
494  }
495  }
496 
497  return success();
498 }
499 
500 //===----------------------------------------------------------------------===//
501 // ForOp
502 //===----------------------------------------------------------------------===//
503 
504 void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
505  Value ub, Value step, BodyBuilderFn bodyBuilder) {
506  OpBuilder::InsertionGuard g(builder);
507  result.addOperands({lb, ub, step});
508  Type t = lb.getType();
509  Region *bodyRegion = result.addRegion();
510  Block *bodyBlock = builder.createBlock(bodyRegion);
511  bodyBlock->addArgument(t, result.location);
512 
513  // Create the default terminator if the builder is not provided.
514  if (!bodyBuilder) {
515  ForOp::ensureTerminator(*bodyRegion, builder, result.location);
516  } else {
517  OpBuilder::InsertionGuard guard(builder);
518  builder.setInsertionPointToStart(bodyBlock);
519  bodyBuilder(builder, result.location, bodyBlock->getArgument(0));
520  }
521 }
522 
523 void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}
524 
525 ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
526  Builder &builder = parser.getBuilder();
527  Type type;
528 
529  OpAsmParser::Argument inductionVariable;
530  OpAsmParser::UnresolvedOperand lb, ub, step;
531 
532  // Parse the induction variable followed by '='.
533  if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
534  // Parse loop bounds.
535  parser.parseOperand(lb) || parser.parseKeyword("to") ||
536  parser.parseOperand(ub) || parser.parseKeyword("step") ||
537  parser.parseOperand(step))
538  return failure();
539 
540  // Parse the optional initial iteration arguments.
542  regionArgs.push_back(inductionVariable);
543 
544  // Parse optional type, else assume Index.
545  if (parser.parseOptionalColon())
546  type = builder.getIndexType();
547  else if (parser.parseType(type))
548  return failure();
549 
550  // Resolve input operands.
551  regionArgs.front().type = type;
552  if (parser.resolveOperand(lb, type, result.operands) ||
553  parser.resolveOperand(ub, type, result.operands) ||
554  parser.resolveOperand(step, type, result.operands))
555  return failure();
556 
557  // Parse the body region.
558  Region *body = result.addRegion();
559  if (parser.parseRegion(*body, regionArgs))
560  return failure();
561 
562  ForOp::ensureTerminator(*body, builder, result.location);
563 
564  // Parse the optional attribute list.
565  if (parser.parseOptionalAttrDict(result.attributes))
566  return failure();
567 
568  return success();
569 }
570 
571 void ForOp::print(OpAsmPrinter &p) {
572  p << " " << getInductionVar() << " = " << getLowerBound() << " to "
573  << getUpperBound() << " step " << getStep();
574 
575  p << ' ';
576  if (Type t = getInductionVar().getType(); !t.isIndex())
577  p << " : " << t << ' ';
578  p.printRegion(getRegion(),
579  /*printEntryBlockArgs=*/false,
580  /*printBlockTerminators=*/false);
581  p.printOptionalAttrDict((*this)->getAttrs());
582 }
583 
584 LogicalResult ForOp::verifyRegions() {
585  // Check that the body defines as single block argument for the induction
586  // variable.
587  if (getInductionVar().getType() != getLowerBound().getType())
588  return emitOpError(
589  "expected induction variable to be same type as bounds and step");
590 
591  return success();
592 }
593 
594 //===----------------------------------------------------------------------===//
595 // CallOp
596 //===----------------------------------------------------------------------===//
597 
598 LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
599  // Check that the callee attribute was specified.
600  auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");
601  if (!fnAttr)
602  return emitOpError("requires a 'callee' symbol reference attribute");
603  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
604  if (!fn)
605  return emitOpError() << "'" << fnAttr.getValue()
606  << "' does not reference a valid function";
607 
608  // Verify that the operand and result types match the callee.
609  auto fnType = fn.getFunctionType();
610  if (fnType.getNumInputs() != getNumOperands())
611  return emitOpError("incorrect number of operands for callee");
612 
613  for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)
614  if (getOperand(i).getType() != fnType.getInput(i))
615  return emitOpError("operand type mismatch: expected operand type ")
616  << fnType.getInput(i) << ", but provided "
617  << getOperand(i).getType() << " for operand number " << i;
618 
619  if (fnType.getNumResults() != getNumResults())
620  return emitOpError("incorrect number of results for callee");
621 
622  for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)
623  if (getResult(i).getType() != fnType.getResult(i)) {
624  auto diag = emitOpError("result type mismatch at index ") << i;
625  diag.attachNote() << " op result types: " << getResultTypes();
626  diag.attachNote() << "function result types: " << fnType.getResults();
627  return diag;
628  }
629 
630  return success();
631 }
632 
633 FunctionType CallOp::getCalleeType() {
634  return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
635 }
636 
637 //===----------------------------------------------------------------------===//
638 // DeclareFuncOp
639 //===----------------------------------------------------------------------===//
640 
641 LogicalResult
642 DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
643  // Check that the sym_name attribute was specified.
644  auto fnAttr = getSymNameAttr();
645  if (!fnAttr)
646  return emitOpError("requires a 'sym_name' symbol reference attribute");
647  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
648  if (!fn)
649  return emitOpError() << "'" << fnAttr.getValue()
650  << "' does not reference a valid function";
651 
652  return success();
653 }
654 
655 //===----------------------------------------------------------------------===//
656 // FuncOp
657 //===----------------------------------------------------------------------===//
658 
659 void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
660  FunctionType type, ArrayRef<NamedAttribute> attrs,
661  ArrayRef<DictionaryAttr> argAttrs) {
662  state.addAttribute(SymbolTable::getSymbolAttrName(),
663  builder.getStringAttr(name));
664  state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
665  state.attributes.append(attrs.begin(), attrs.end());
666  state.addRegion();
667 
668  if (argAttrs.empty())
669  return;
670  assert(type.getNumInputs() == argAttrs.size());
672  builder, state, argAttrs, /*resultAttrs=*/{},
673  getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
674 }
675 
676 ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
677  auto buildFuncType =
678  [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
680  std::string &) { return builder.getFunctionType(argTypes, results); };
681 
683  parser, result, /*allowVariadic=*/false,
684  getFunctionTypeAttrName(result.name), buildFuncType,
685  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
686 }
687 
688 void FuncOp::print(OpAsmPrinter &p) {
690  p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
691  getArgAttrsAttrName(), getResAttrsAttrName());
692 }
693 
694 LogicalResult FuncOp::verify() {
695  if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {
696  return emitOpError("cannot have lvalue type as argument");
697  }
698 
699  if (getNumResults() > 1)
700  return emitOpError("requires zero or exactly one result, but has ")
701  << getNumResults();
702 
703  if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
704  return emitOpError("cannot return array type");
705 
706  return success();
707 }
708 
709 //===----------------------------------------------------------------------===//
710 // ReturnOp
711 //===----------------------------------------------------------------------===//
712 
713 LogicalResult ReturnOp::verify() {
714  auto function = cast<FuncOp>((*this)->getParentOp());
715 
716  // The operand number and types must match the function signature.
717  if (getNumOperands() != function.getNumResults())
718  return emitOpError("has ")
719  << getNumOperands() << " operands, but enclosing function (@"
720  << function.getName() << ") returns " << function.getNumResults();
721 
722  if (function.getNumResults() == 1)
723  if (getOperand().getType() != function.getResultTypes()[0])
724  return emitError() << "type of the return operand ("
725  << getOperand().getType()
726  << ") doesn't match function result type ("
727  << function.getResultTypes()[0] << ")"
728  << " in function @" << function.getName();
729  return success();
730 }
731 
732 //===----------------------------------------------------------------------===//
733 // IfOp
734 //===----------------------------------------------------------------------===//
735 
736 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
737  bool addThenBlock, bool addElseBlock) {
738  assert((!addElseBlock || addThenBlock) &&
739  "must not create else block w/o then block");
740  result.addOperands(cond);
741 
742  // Add regions and blocks.
743  OpBuilder::InsertionGuard guard(builder);
744  Region *thenRegion = result.addRegion();
745  if (addThenBlock)
746  builder.createBlock(thenRegion);
747  Region *elseRegion = result.addRegion();
748  if (addElseBlock)
749  builder.createBlock(elseRegion);
750 }
751 
752 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
753  bool withElseRegion) {
754  result.addOperands(cond);
755 
756  // Build then region.
757  OpBuilder::InsertionGuard guard(builder);
758  Region *thenRegion = result.addRegion();
759  builder.createBlock(thenRegion);
760 
761  // Build else region.
762  Region *elseRegion = result.addRegion();
763  if (withElseRegion) {
764  builder.createBlock(elseRegion);
765  }
766 }
767 
768 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
769  function_ref<void(OpBuilder &, Location)> thenBuilder,
770  function_ref<void(OpBuilder &, Location)> elseBuilder) {
771  assert(thenBuilder && "the builder callback for 'then' must be present");
772  result.addOperands(cond);
773 
774  // Build then region.
775  OpBuilder::InsertionGuard guard(builder);
776  Region *thenRegion = result.addRegion();
777  builder.createBlock(thenRegion);
778  thenBuilder(builder, result.location);
779 
780  // Build else region.
781  Region *elseRegion = result.addRegion();
782  if (elseBuilder) {
783  builder.createBlock(elseRegion);
784  elseBuilder(builder, result.location);
785  }
786 }
787 
788 ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) {
789  // Create the regions for 'then'.
790  result.regions.reserve(2);
791  Region *thenRegion = result.addRegion();
792  Region *elseRegion = result.addRegion();
793 
794  Builder &builder = parser.getBuilder();
796  Type i1Type = builder.getIntegerType(1);
797  if (parser.parseOperand(cond) ||
798  parser.resolveOperand(cond, i1Type, result.operands))
799  return failure();
800  // Parse the 'then' region.
801  if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))
802  return failure();
803  IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
804 
805  // If we find an 'else' keyword then parse the 'else' region.
806  if (!parser.parseOptionalKeyword("else")) {
807  if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))
808  return failure();
809  IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
810  }
811 
812  // Parse the optional attribute list.
813  if (parser.parseOptionalAttrDict(result.attributes))
814  return failure();
815  return success();
816 }
817 
818 void IfOp::print(OpAsmPrinter &p) {
819  bool printBlockTerminators = false;
820 
821  p << " " << getCondition();
822  p << ' ';
823  p.printRegion(getThenRegion(),
824  /*printEntryBlockArgs=*/false,
825  /*printBlockTerminators=*/printBlockTerminators);
826 
827  // Print the 'else' regions if it exists and has a block.
828  Region &elseRegion = getElseRegion();
829  if (!elseRegion.empty()) {
830  p << " else ";
831  p.printRegion(elseRegion,
832  /*printEntryBlockArgs=*/false,
833  /*printBlockTerminators=*/printBlockTerminators);
834  }
835 
836  p.printOptionalAttrDict((*this)->getAttrs());
837 }
838 
839 /// Given the region at `index`, or the parent operation if `index` is None,
840 /// return the successor regions. These are the regions that may be selected
841 /// during the flow of control. `operands` is a set of optional attributes
842 /// that correspond to a constant value for each operand, or null if that
843 /// operand is not a constant.
844 void IfOp::getSuccessorRegions(RegionBranchPoint point,
846  // The `then` and the `else` region branch back to the parent operation.
847  if (!point.isParent()) {
848  regions.push_back(
849  RegionSuccessor(getOperation(), getOperation()->getResults()));
850  return;
851  }
852 
853  regions.push_back(RegionSuccessor(&getThenRegion()));
854 
855  // Don't consider the else region if it is empty.
856  Region *elseRegion = &this->getElseRegion();
857  if (elseRegion->empty())
858  regions.push_back(
859  RegionSuccessor(getOperation(), getOperation()->getResults()));
860  else
861  regions.push_back(RegionSuccessor(elseRegion));
862 }
863 
864 void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,
866  FoldAdaptor adaptor(operands, *this);
867  auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
868  if (!boolAttr || boolAttr.getValue())
869  regions.emplace_back(&getThenRegion());
870 
871  // If the else region is empty, execution continues after the parent op.
872  if (!boolAttr || !boolAttr.getValue()) {
873  if (!getElseRegion().empty())
874  regions.emplace_back(&getElseRegion());
875  else
876  regions.emplace_back(getOperation(), getOperation()->getResults());
877  }
878 }
879 
880 void IfOp::getRegionInvocationBounds(
881  ArrayRef<Attribute> operands,
882  SmallVectorImpl<InvocationBounds> &invocationBounds) {
883  if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
884  // If the condition is known, then one region is known to be executed once
885  // and the other zero times.
886  invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
887  invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
888  } else {
889  // Non-constant condition. Each region may be executed 0 or 1 times.
890  invocationBounds.assign(2, {0, 1});
891  }
892 }
893 
894 //===----------------------------------------------------------------------===//
895 // IncludeOp
896 //===----------------------------------------------------------------------===//
897 
899  bool standardInclude = getIsStandardInclude();
900 
901  p << " ";
902  if (standardInclude)
903  p << "<";
904  p << "\"" << getInclude() << "\"";
905  if (standardInclude)
906  p << ">";
907 }
908 
909 ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {
910  bool standardInclude = !parser.parseOptionalLess();
911 
912  StringAttr include;
913  OptionalParseResult includeParseResult =
914  parser.parseOptionalAttribute(include, "include", result.attributes);
915  if (!includeParseResult.has_value())
916  return parser.emitError(parser.getNameLoc()) << "expected string attribute";
917 
918  if (standardInclude && parser.parseOptionalGreater())
919  return parser.emitError(parser.getNameLoc())
920  << "expected trailing '>' for standard include";
921 
922  if (standardInclude)
923  result.addAttribute("is_standard_include",
924  UnitAttr::get(parser.getContext()));
925 
926  return success();
927 }
928 
929 //===----------------------------------------------------------------------===//
930 // LiteralOp
931 //===----------------------------------------------------------------------===//
932 
933 /// The literal op requires a non-empty value.
934 LogicalResult emitc::LiteralOp::verify() {
935  if (getValue().empty())
936  return emitOpError() << "value must not be empty";
937  return success();
938 }
939 //===----------------------------------------------------------------------===//
940 // SubOp
941 //===----------------------------------------------------------------------===//
942 
943 LogicalResult SubOp::verify() {
944  Type lhsType = getLhs().getType();
945  Type rhsType = getRhs().getType();
946  Type resultType = getResult().getType();
947 
948  if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
949  return emitOpError("rhs can only be a pointer if lhs is a pointer");
950 
951  if (isa<emitc::PointerType>(lhsType) &&
952  !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
953  return emitOpError("requires that rhs is an integer, pointer or of opaque "
954  "type if lhs is a pointer");
955 
956  if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
957  !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))
958  return emitOpError("requires that the result is an integer, ptrdiff_t or "
959  "of opaque type if lhs and rhs are pointers");
960  return success();
961 }
962 
963 //===----------------------------------------------------------------------===//
964 // VariableOp
965 //===----------------------------------------------------------------------===//
966 
967 LogicalResult emitc::VariableOp::verify() {
968  return verifyInitializationAttribute(getOperation(), getValueAttr());
969 }
970 
971 //===----------------------------------------------------------------------===//
972 // YieldOp
973 //===----------------------------------------------------------------------===//
974 
975 LogicalResult emitc::YieldOp::verify() {
976  Value result = getResult();
977  Operation *containingOp = getOperation()->getParentOp();
978 
979  if (!isa<DoOp>(containingOp) && result && containingOp->getNumResults() != 1)
980  return emitOpError() << "yields a value not returned by parent";
981 
982  if (!isa<DoOp>(containingOp) && !result && containingOp->getNumResults() != 0)
983  return emitOpError() << "does not yield a value to be returned by parent";
984 
985  return success();
986 }
987 
988 //===----------------------------------------------------------------------===//
989 // SubscriptOp
990 //===----------------------------------------------------------------------===//
991 
992 LogicalResult emitc::SubscriptOp::verify() {
993  // Checks for array operand.
994  if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {
995  // Check number of indices.
996  if (getIndices().size() != (size_t)arrayType.getRank()) {
997  return emitOpError() << "on array operand requires number of indices ("
998  << getIndices().size()
999  << ") to match the rank of the array type ("
1000  << arrayType.getRank() << ")";
1001  }
1002  // Check types of index operands.
1003  for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {
1004  Type type = getIndices()[i].getType();
1005  if (!isIntegerIndexOrOpaqueType(type)) {
1006  return emitOpError() << "on array operand requires index operand " << i
1007  << " to be integer-like, but got " << type;
1008  }
1009  }
1010  // Check element type.
1011  Type elementType = arrayType.getElementType();
1012  Type resultType = getType().getValueType();
1013  if (elementType != resultType) {
1014  return emitOpError() << "on array operand requires element type ("
1015  << elementType << ") and result type (" << resultType
1016  << ") to match";
1017  }
1018  return success();
1019  }
1020 
1021  // Checks for pointer operand.
1022  if (auto pointerType =
1023  llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {
1024  // Check number of indices.
1025  if (getIndices().size() != 1) {
1026  return emitOpError()
1027  << "on pointer operand requires one index operand, but got "
1028  << getIndices().size();
1029  }
1030  // Check types of index operand.
1031  Type type = getIndices()[0].getType();
1032  if (!isIntegerIndexOrOpaqueType(type)) {
1033  return emitOpError() << "on pointer operand requires index operand to be "
1034  "integer-like, but got "
1035  << type;
1036  }
1037  // Check pointee type.
1038  Type pointeeType = pointerType.getPointee();
1039  Type resultType = getType().getValueType();
1040  if (pointeeType != resultType) {
1041  return emitOpError() << "on pointer operand requires pointee type ("
1042  << pointeeType << ") and result type (" << resultType
1043  << ") to match";
1044  }
1045  return success();
1046  }
1047 
1048  // The operand has opaque type, so we can't assume anything about the number
1049  // or types of index operands.
1050  return success();
1051 }
1052 
1053 //===----------------------------------------------------------------------===//
1054 // VerbatimOp
1055 //===----------------------------------------------------------------------===//
1056 
1057 LogicalResult emitc::VerbatimOp::verify() {
1058  auto errorCallback = [&]() -> InFlightDiagnostic {
1059  return this->emitOpError();
1060  };
1061  FailureOr<SmallVector<ReplacementItem>> fmt =
1062  ::parseFormatString(getValue(), getFmtArgs(), errorCallback);
1063  if (failed(fmt))
1064  return failure();
1065 
1066  size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) {
1067  return std::holds_alternative<Placeholder>(item);
1068  });
1069 
1070  if (numPlaceholders != getFmtArgs().size()) {
1071  return emitOpError()
1072  << "requires operands for each placeholder in the format string";
1073  }
1074  return success();
1075 }
1076 
1077 FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {
1078  // Error checking is done in verify.
1079  return ::parseFormatString(getValue(), getFmtArgs());
1080 }
1081 
1082 //===----------------------------------------------------------------------===//
1083 // EmitC Enums
1084 //===----------------------------------------------------------------------===//
1085 
1086 #include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
1087 
1088 //===----------------------------------------------------------------------===//
1089 // EmitC Attributes
1090 //===----------------------------------------------------------------------===//
1091 
1092 #define GET_ATTRDEF_CLASSES
1093 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
1094 
1095 //===----------------------------------------------------------------------===//
1096 // EmitC Types
1097 //===----------------------------------------------------------------------===//
1098 
1099 #define GET_TYPEDEF_CLASSES
1100 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
1101 
1102 //===----------------------------------------------------------------------===//
1103 // ArrayType
1104 //===----------------------------------------------------------------------===//
1105 
1107  if (parser.parseLess())
1108  return Type();
1109 
1110  SmallVector<int64_t, 4> dimensions;
1111  if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,
1112  /*withTrailingX=*/true))
1113  return Type();
1114  // Parse the element type.
1115  auto typeLoc = parser.getCurrentLocation();
1116  Type elementType;
1117  if (parser.parseType(elementType))
1118  return Type();
1119 
1120  // Check that array is formed from allowed types.
1121  if (!isValidElementType(elementType))
1122  return parser.emitError(typeLoc, "invalid array element type '")
1123  << elementType << "'",
1124  Type();
1125  if (parser.parseGreater())
1126  return Type();
1127  return parser.getChecked<ArrayType>(dimensions, elementType);
1128 }
1129 
1130 void emitc::ArrayType::print(AsmPrinter &printer) const {
1131  printer << "<";
1132  for (int64_t dim : getShape()) {
1133  printer << dim << 'x';
1134  }
1135  printer.printType(getElementType());
1136  printer << ">";
1137 }
1138 
1139 LogicalResult emitc::ArrayType::verify(
1141  ::llvm::ArrayRef<int64_t> shape, Type elementType) {
1142  if (shape.empty())
1143  return emitError() << "shape must not be empty";
1144 
1145  for (int64_t dim : shape) {
1146  if (dim < 0)
1147  return emitError() << "dimensions must have non-negative size";
1148  }
1149 
1150  if (!elementType)
1151  return emitError() << "element type must not be none";
1152 
1153  if (!isValidElementType(elementType))
1154  return emitError() << "invalid array element type";
1155 
1156  return success();
1157 }
1158 
1159 emitc::ArrayType
1160 emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
1161  Type elementType) const {
1162  if (!shape)
1163  return emitc::ArrayType::get(getShape(), elementType);
1164  return emitc::ArrayType::get(*shape, elementType);
1165 }
1166 
1167 //===----------------------------------------------------------------------===//
1168 // LValueType
1169 //===----------------------------------------------------------------------===//
1170 
1171 LogicalResult mlir::emitc::LValueType::verify(
1173  mlir::Type value) {
1174  // Check that the wrapped type is valid. This especially forbids nested
1175  // lvalue types.
1176  if (!isSupportedEmitCType(value))
1177  return emitError()
1178  << "!emitc.lvalue must wrap supported emitc type, but got " << value;
1179 
1180  if (llvm::isa<emitc::ArrayType>(value))
1181  return emitError() << "!emitc.lvalue cannot wrap !emitc.array type";
1182 
1183  return success();
1184 }
1185 
1186 //===----------------------------------------------------------------------===//
1187 // OpaqueType
1188 //===----------------------------------------------------------------------===//
1189 
1190 LogicalResult mlir::emitc::OpaqueType::verify(
1192  llvm::StringRef value) {
1193  if (value.empty()) {
1194  return emitError() << "expected non empty string in !emitc.opaque type";
1195  }
1196  if (value.back() == '*') {
1197  return emitError() << "pointer not allowed as outer type with "
1198  "!emitc.opaque, use !emitc.ptr instead";
1199  }
1200  return success();
1201 }
1202 
1203 //===----------------------------------------------------------------------===//
1204 // PointerType
1205 //===----------------------------------------------------------------------===//
1206 
1207 LogicalResult mlir::emitc::PointerType::verify(
1209  if (llvm::isa<emitc::LValueType>(value))
1210  return emitError() << "pointers to lvalues are not allowed";
1211 
1212  return success();
1213 }
1214 
1215 //===----------------------------------------------------------------------===//
1216 // GlobalOp
1217 //===----------------------------------------------------------------------===//
1219  TypeAttr type,
1220  Attribute initialValue) {
1221  p << type;
1222  if (initialValue) {
1223  p << " = ";
1224  p.printAttributeWithoutType(initialValue);
1225  }
1226 }
1227 
1229  if (auto array = llvm::dyn_cast<ArrayType>(type))
1230  return RankedTensorType::get(array.getShape(), array.getElementType());
1231  return type;
1232 }
1233 
1234 static ParseResult
1236  Attribute &initialValue) {
1237  Type type;
1238  if (parser.parseType(type))
1239  return failure();
1240 
1241  typeAttr = TypeAttr::get(type);
1242 
1243  if (parser.parseOptionalEqual())
1244  return success();
1245 
1246  if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))
1247  return failure();
1248 
1249  if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1250  initialValue))
1251  return parser.emitError(parser.getNameLoc())
1252  << "initial value should be a integer, float, elements or opaque "
1253  "attribute";
1254  return success();
1255 }
1256 
1257 LogicalResult GlobalOp::verify() {
1258  if (!isSupportedEmitCType(getType())) {
1259  return emitOpError("expected valid emitc type");
1260  }
1261  if (getInitialValue().has_value()) {
1262  Attribute initValue = getInitialValue().value();
1263  // Check that the type of the initial value is compatible with the type of
1264  // the global variable.
1265  if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1266  auto arrayType = llvm::dyn_cast<ArrayType>(getType());
1267  if (!arrayType)
1268  return emitOpError("expected array type, but got ") << getType();
1269 
1270  Type initType = elementsAttr.getType();
1271  Type tensorType = getInitializerTypeForGlobal(getType());
1272  if (initType != tensorType) {
1273  return emitOpError("initial value expected to be of type ")
1274  << getType() << ", but was of type " << initType;
1275  }
1276  } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1277  if (intAttr.getType() != getType()) {
1278  return emitOpError("initial value expected to be of type ")
1279  << getType() << ", but was of type " << intAttr.getType();
1280  }
1281  } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1282  if (floatAttr.getType() != getType()) {
1283  return emitOpError("initial value expected to be of type ")
1284  << getType() << ", but was of type " << floatAttr.getType();
1285  }
1286  } else if (!isa<emitc::OpaqueAttr>(initValue)) {
1287  return emitOpError("initial value should be a integer, float, elements "
1288  "or opaque attribute, but got ")
1289  << initValue;
1290  }
1291  }
1292  if (getStaticSpecifier() && getExternSpecifier()) {
1293  return emitOpError("cannot have both static and extern specifiers");
1294  }
1295  return success();
1296 }
1297 
1298 //===----------------------------------------------------------------------===//
1299 // GetGlobalOp
1300 //===----------------------------------------------------------------------===//
1301 
1302 LogicalResult
1303 GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1304  // Verify that the type matches the type of the global variable.
1305  auto global =
1306  symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1307  if (!global)
1308  return emitOpError("'")
1309  << getName() << "' does not reference a valid emitc.global";
1310 
1311  Type resultType = getResult().getType();
1312  Type globalType = global.getType();
1313 
1314  // global has array type
1315  if (llvm::isa<ArrayType>(globalType)) {
1316  if (globalType != resultType)
1317  return emitOpError("on array type expects result type ")
1318  << resultType << " to match type " << globalType
1319  << " of the global @" << getName();
1320  return success();
1321  }
1322 
1323  // global has non-array type
1324  auto lvalueType = dyn_cast<LValueType>(resultType);
1325  if (!lvalueType)
1326  return emitOpError("on non-array type expects result type to be an "
1327  "lvalue type for the global @")
1328  << getName();
1329  if (lvalueType.getValueType() != globalType)
1330  return emitOpError("on non-array type expects result inner type ")
1331  << lvalueType.getValueType() << " to match type " << globalType
1332  << " of the global @" << getName();
1333  return success();
1334 }
1335 
1336 //===----------------------------------------------------------------------===//
1337 // SwitchOp
1338 //===----------------------------------------------------------------------===//
1339 
1340 /// Parse the case regions and values.
1341 static ParseResult
1343  SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
1344  SmallVector<int64_t> caseValues;
1345  while (succeeded(parser.parseOptionalKeyword("case"))) {
1346  int64_t value;
1347  Region &region = *caseRegions.emplace_back(std::make_unique<Region>());
1348  if (parser.parseInteger(value) ||
1349  parser.parseRegion(region, /*arguments=*/{}))
1350  return failure();
1351  caseValues.push_back(value);
1352  }
1353  cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);
1354  return success();
1355 }
1356 
1357 /// Print the case regions and values.
1359  DenseI64ArrayAttr cases, RegionRange caseRegions) {
1360  for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {
1361  p.printNewline();
1362  p << "case " << value << ' ';
1363  p.printRegion(*region, /*printEntryBlockArgs=*/false);
1364  }
1365 }
1366 
1367 static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region,
1368  const Twine &name) {
1369  auto yield = dyn_cast<emitc::YieldOp>(region.front().back());
1370  if (!yield)
1371  return op.emitOpError("expected region to end with emitc.yield, but got ")
1372  << region.front().back().getName();
1373 
1374  if (yield.getNumOperands() != 0) {
1375  return (op.emitOpError("expected each region to return ")
1376  << "0 values, but " << name << " returns "
1377  << yield.getNumOperands())
1378  .attachNote(yield.getLoc())
1379  << "see yield operation here";
1380  }
1381 
1382  return success();
1383 }
1384 
1385 LogicalResult emitc::SwitchOp::verify() {
1386  if (!isIntegerIndexOrOpaqueType(getArg().getType()))
1387  return emitOpError("unsupported type ") << getArg().getType();
1388 
1389  if (getCases().size() != getCaseRegions().size()) {
1390  return emitOpError("has ")
1391  << getCaseRegions().size() << " case regions but "
1392  << getCases().size() << " case values";
1393  }
1394 
1395  DenseSet<int64_t> valueSet;
1396  for (int64_t value : getCases())
1397  if (!valueSet.insert(value).second)
1398  return emitOpError("has duplicate case value: ") << value;
1399 
1400  if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))
1401  return failure();
1402 
1403  for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
1404  if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))
1405  return failure();
1406 
1407  return success();
1408 }
1409 
1410 unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }
1411 
1412 Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }
1413 
1414 Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {
1415  assert(idx < getNumCases() && "case index out-of-bounds");
1416  return getCaseRegions()[idx].front();
1417 }
1418 
1419 void SwitchOp::getSuccessorRegions(
1421  llvm::append_range(successors, getRegions());
1422 }
1423 
1424 void SwitchOp::getEntrySuccessorRegions(
1425  ArrayRef<Attribute> operands,
1426  SmallVectorImpl<RegionSuccessor> &successors) {
1427  FoldAdaptor adaptor(operands, *this);
1428 
1429  // If a constant was not provided, all regions are possible successors.
1430  auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
1431  if (!arg) {
1432  llvm::append_range(successors, getRegions());
1433  return;
1434  }
1435 
1436  // Otherwise, try to find a case with a matching value. If not, the
1437  // default region is the only successor.
1438  for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
1439  if (caseValue == arg.getInt()) {
1440  successors.emplace_back(&caseRegion);
1441  return;
1442  }
1443  }
1444  successors.emplace_back(&getDefaultRegion());
1445 }
1446 
1447 void SwitchOp::getRegionInvocationBounds(
1449  auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
1450  if (!operandValue) {
1451  // All regions are invoked at most once.
1452  bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1453  return;
1454  }
1455 
1456  unsigned liveIndex = getNumRegions() - 1;
1457  const auto *iteratorToInt = llvm::find(getCases(), operandValue.getInt());
1458 
1459  liveIndex = iteratorToInt != getCases().end()
1460  ? std::distance(getCases().begin(), iteratorToInt)
1461  : liveIndex;
1462 
1463  for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
1464  ++regIndex)
1465  bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
1466 }
1467 
1468 //===----------------------------------------------------------------------===//
1469 // FileOp
1470 //===----------------------------------------------------------------------===//
1471 void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {
1472  state.addRegion()->emplaceBlock();
1473  state.attributes.push_back(
1474  builder.getNamedAttr("id", builder.getStringAttr(id)));
1475 }
1476 
1477 //===----------------------------------------------------------------------===//
1478 // FieldOp
1479 //===----------------------------------------------------------------------===//
1480 
1482  TypeAttr type,
1483  Attribute initialValue) {
1484  p << type;
1485  if (initialValue) {
1486  p << " = ";
1487  p.printAttributeWithoutType(initialValue);
1488  }
1489 }
1490 
1492  if (auto array = llvm::dyn_cast<ArrayType>(type))
1493  return RankedTensorType::get(array.getShape(), array.getElementType());
1494  return type;
1495 }
1496 
1497 static ParseResult
1499  Attribute &initialValue) {
1500  Type type;
1501  if (parser.parseType(type))
1502  return failure();
1503 
1504  typeAttr = TypeAttr::get(type);
1505 
1506  if (parser.parseOptionalEqual())
1507  return success();
1508 
1509  if (parser.parseAttribute(initialValue, getInitializerTypeForField(type)))
1510  return failure();
1511 
1512  if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1513  initialValue))
1514  return parser.emitError(parser.getNameLoc())
1515  << "initial value should be a integer, float, elements or opaque "
1516  "attribute";
1517  return success();
1518 }
1519 
1520 LogicalResult FieldOp::verify() {
1521  if (!isSupportedEmitCType(getType()))
1522  return emitOpError("expected valid emitc type");
1523 
1524  Operation *parentOp = getOperation()->getParentOp();
1525  if (!parentOp || !isa<emitc::ClassOp>(parentOp))
1526  return emitOpError("field must be nested within an emitc.class operation");
1527 
1528  StringAttr symName = getSymNameAttr();
1529  if (!symName || symName.getValue().empty())
1530  return emitOpError("field must have a non-empty symbol name");
1531 
1532  return success();
1533 }
1534 
1535 //===----------------------------------------------------------------------===//
1536 // GetFieldOp
1537 //===----------------------------------------------------------------------===//
1538 
1539 LogicalResult GetFieldOp::verify() {
1540  auto parentClassOp = getOperation()->getParentOfType<emitc::ClassOp>();
1541  if (!parentClassOp.getOperation())
1542  return emitOpError(" must be nested within an emitc.class operation");
1543 
1544  return success();
1545 }
1546 
1547 LogicalResult GetFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1548  mlir::FlatSymbolRefAttr fieldNameAttr = getFieldNameAttr();
1549  FieldOp fieldOp =
1550  symbolTable.lookupNearestSymbolFrom<FieldOp>(*this, fieldNameAttr);
1551  if (!fieldOp)
1552  return emitOpError("field '")
1553  << fieldNameAttr << "' not found in the class";
1554 
1555  Type getFieldResultType = getResult().getType();
1556  Type fieldType = fieldOp.getType();
1557 
1558  if (fieldType != getFieldResultType)
1559  return emitOpError("result type ")
1560  << getFieldResultType << " does not match field '" << fieldNameAttr
1561  << "' type " << fieldType;
1562 
1563  return success();
1564 }
1565 
1566 //===----------------------------------------------------------------------===//
1567 // DoOp
1568 //===----------------------------------------------------------------------===//
1569 
1570 void DoOp::print(OpAsmPrinter &p) {
1571  p << ' ';
1572  p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
1573  p << " while ";
1574  p.printRegion(getConditionRegion());
1575  p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs());
1576 }
1577 
1578 LogicalResult emitc::DoOp::verify() {
1579  Block &condBlock = getConditionRegion().front();
1580 
1581  if (condBlock.getOperations().size() != 2)
1582  return emitOpError(
1583  "condition region must contain exactly two operations: "
1584  "'emitc.expression' followed by 'emitc.yield', but found ")
1585  << condBlock.getOperations().size() << " operations";
1586 
1587  Operation &first = condBlock.front();
1588  auto exprOp = dyn_cast<emitc::ExpressionOp>(first);
1589  if (!exprOp)
1590  return emitOpError("expected first op in condition region to be "
1591  "'emitc.expression', but got ")
1592  << first.getName();
1593 
1594  if (!exprOp.getResult().getType().isInteger(1))
1595  return emitOpError("emitc.expression in condition region must return "
1596  "'i1', but returns ")
1597  << exprOp.getResult().getType();
1598 
1599  Operation &last = condBlock.back();
1600  auto condYield = dyn_cast<emitc::YieldOp>(last);
1601  if (!condYield)
1602  return emitOpError("expected last op in condition region to be "
1603  "'emitc.yield', but got ")
1604  << last.getName();
1605 
1606  if (condYield.getNumOperands() != 1)
1607  return emitOpError("expected condition region to return 1 value, but "
1608  "it returns ")
1609  << condYield.getNumOperands() << " values";
1610 
1611  if (condYield.getOperand(0) != exprOp.getResult())
1612  return emitError("'emitc.yield' must return result of "
1613  "'emitc.expression' from this condition region");
1614 
1615  Block &bodyBlock = getBodyRegion().front();
1616  if (bodyBlock.mightHaveTerminator())
1617  return emitOpError("body region must not contain terminator");
1618 
1619  return success();
1620 }
1621 
1622 ParseResult DoOp::parse(OpAsmParser &parser, OperationState &result) {
1623  Region *bodyRegion = result.addRegion();
1624  Region *condRegion = result.addRegion();
1625 
1626  if (parser.parseRegion(*bodyRegion) || parser.parseKeyword("while") ||
1627  parser.parseRegion(*condRegion))
1628  return failure();
1629 
1630  if (bodyRegion->empty())
1631  bodyRegion->emplaceBlock();
1632 
1633  return parser.parseOptionalAttrDictWithKeyword(result.attributes);
1634 }
1635 
1636 //===----------------------------------------------------------------------===//
1637 // TableGen'd op method definitions
1638 //===----------------------------------------------------------------------===//
1639 
1640 #include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"
1641 
1642 #define GET_OP_CLASSES
1643 #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:757
static std::optional< int64_t > getLowerBound(Value iv)
Gets the constant lower bound on an iv.
Definition: AffineOps.cpp:749
static bool hasSideEffects(Operation *op)
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:144
static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region, const Twine &name)
Definition: EmitC.cpp:1367
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition: EmitC.cpp:1235
static ParseResult parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, SmallVectorImpl< std::unique_ptr< Region >> &caseRegions)
Parse the case regions and values.
Definition: EmitC.cpp:1342
static Type getInitializerTypeForField(Type type)
Definition: EmitC.cpp:1491
FailureOr< SmallVector< ReplacementItem > > parseFormatString(StringRef toParse, ArgType fmtArgs, llvm::function_ref< mlir::InFlightDiagnostic()> emitError={})
Parse a format string and return a list of its parts.
Definition: EmitC.cpp:179
static ParseResult parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition: EmitC.cpp:1498
static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, TypeAttr type, Attribute initialValue)
Definition: EmitC.cpp:1218
static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op, TypeAttr type, Attribute initialValue)
Definition: EmitC.cpp:1481
static void printSwitchCases(OpAsmPrinter &p, Operation *op, DenseI64ArrayAttr cases, RegionRange caseRegions)
Print the case regions and values.
Definition: EmitC.cpp:1358
static Type getInitializerTypeForGlobal(Type type)
Definition: EmitC.cpp:1228
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:51
static MLIRContext * getContext(OpFoldResult val)
static Type getElementType(Type type)
Determine the element type of type.
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Definition: Traits.cpp:117
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:72
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 ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
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:244
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:153
OpListType & getOperations()
Definition: Block.h:137
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
Definition: Block.cpp:250
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:212
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:51
UnitAttr getUnitAttr()
Definition: Builders.cpp:98
DenseI64ArrayAttr getDenseI64ArrayAttr(ArrayRef< int64_t > values)
Definition: Builders.cpp:167
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:262
IndexType getIndexType()
Definition: Builders.cpp:51
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition: Builders.cpp:94
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:316
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:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
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.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
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.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void shadowRegionArgs(Region &region, ValueRange namesToUse)=0
Renumber the arguments for the specified region to the same names as the SSA values in namesToUse.
virtual void printNewline()=0
Print a newline and indent the printer to the start of the current operation.
void printOperands(const ContainerType &container)
Print a comma separated list of operands.
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with 'attribute...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Definition: AsmPrinter.cpp:94
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:348
This class helps build Operations.
Definition: Builders.h:207
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition: Builders.cpp:430
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition: Builders.h:431
This class represents a single result from folding an operation.
Definition: OpDefinition.h:272
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
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:378
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:673
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:40
bool has_value() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:50
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
Block & emplaceBlock()
Definition: Region.h:46
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
virtual 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
bool use_empty() const
Returns true if this value has no uses.
Definition: Value.h:208
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:18
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:4530
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:57
bool isFundamentalType(mlir::Type type)
Determines whether type is a valid fundamental C++ type in EmitC.
Definition: EmitC.cpp:136
bool isSupportedFloatType(mlir::Type type)
Determines whether type is a valid floating-point type in EmitC.
Definition: EmitC.cpp:116
bool isSupportedEmitCType(mlir::Type type)
Determines whether type is valid in EmitC.
Definition: EmitC.cpp:61
bool isPointerWideType(mlir::Type type)
Determines whether type is a emitc.size_t/ssize_t type.
Definition: EmitC.cpp:131
bool isIntegerIndexOrOpaqueType(Type type)
Determines whether type is integer like, i.e.
Definition: EmitC.cpp:111
bool isSupportedIntegerType(mlir::Type type)
Determines whether type is a valid integer type in EmitC.
Definition: EmitC.cpp:95
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:21
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:561
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:304
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:498
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:423
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.
void addTypes(ArrayRef< Type > newTypes)
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.