MLIR  19.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 
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 builder.create<emitc::ConstantOp>(loc, type, value);
53 }
54 
55 /// Default callback for builders of ops carrying a region. Inserts a yield
56 /// without arguments.
58  builder.create<emitc::YieldOp>(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 32:
120  case 64:
121  return true;
122  default:
123  return false;
124  }
125  }
126  return false;
127 }
128 
130  return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>(
131  type);
132 }
133 
134 /// Check that the type of the initial value is compatible with the operations
135 /// result type.
137  Attribute value) {
138  assert(op->getNumResults() == 1 && "operation must have 1 result");
139 
140  if (llvm::isa<emitc::OpaqueAttr>(value))
141  return success();
142 
143  if (llvm::isa<StringAttr>(value))
144  return op->emitOpError()
145  << "string attributes are not supported, use #emitc.opaque instead";
146 
147  Type resultType = op->getResult(0).getType();
148  Type attrType = cast<TypedAttr>(value).getType();
149 
150  if (isPointerWideType(resultType) && attrType.isIndex())
151  return success();
152 
153  if (resultType != attrType)
154  return op->emitOpError()
155  << "requires attribute to either be an #emitc.opaque attribute or "
156  "it's type ("
157  << attrType << ") to match the op's result type (" << resultType
158  << ")";
159 
160  return success();
161 }
162 
163 //===----------------------------------------------------------------------===//
164 // AddOp
165 //===----------------------------------------------------------------------===//
166 
168  Type lhsType = getLhs().getType();
169  Type rhsType = getRhs().getType();
170 
171  if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType))
172  return emitOpError("requires that at most one operand is a pointer");
173 
174  if ((isa<emitc::PointerType>(lhsType) &&
175  !isa<IntegerType, emitc::OpaqueType>(rhsType)) ||
176  (isa<emitc::PointerType>(rhsType) &&
177  !isa<IntegerType, emitc::OpaqueType>(lhsType)))
178  return emitOpError("requires that one operand is an integer or of opaque "
179  "type if the other is a pointer");
180 
181  return success();
182 }
183 
184 //===----------------------------------------------------------------------===//
185 // ApplyOp
186 //===----------------------------------------------------------------------===//
187 
189  StringRef applicableOperatorStr = getApplicableOperator();
190 
191  // Applicable operator must not be empty.
192  if (applicableOperatorStr.empty())
193  return emitOpError("applicable operator must not be empty");
194 
195  // Only `*` and `&` are supported.
196  if (applicableOperatorStr != "&" && applicableOperatorStr != "*")
197  return emitOpError("applicable operator is illegal");
198 
199  Operation *op = getOperand().getDefiningOp();
200  if (op && dyn_cast<ConstantOp>(op))
201  return emitOpError("cannot apply to constant");
202 
203  return success();
204 }
205 
206 //===----------------------------------------------------------------------===//
207 // AssignOp
208 //===----------------------------------------------------------------------===//
209 
210 /// The assign op requires that the assigned value's type matches the
211 /// assigned-to variable type.
213  Value variable = getVar();
214  Operation *variableDef = variable.getDefiningOp();
215  if (!variableDef ||
216  !llvm::isa<emitc::VariableOp, emitc::SubscriptOp>(variableDef))
217  return emitOpError() << "requires first operand (" << variable
218  << ") to be a Variable or subscript";
219 
220  Value value = getValue();
221  if (variable.getType() != value.getType())
222  return emitOpError() << "requires value's type (" << value.getType()
223  << ") to match variable's type (" << variable.getType()
224  << ")";
225  if (isa<ArrayType>(variable.getType()))
226  return emitOpError() << "cannot assign to array type";
227  return success();
228 }
229 
230 //===----------------------------------------------------------------------===//
231 // CastOp
232 //===----------------------------------------------------------------------===//
233 
234 bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
235  Type input = inputs.front(), output = outputs.front();
236 
237  return (
239  emitc::isSupportedFloatType(input) || isa<emitc::PointerType>(input)) &&
241  emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output)));
242 }
243 
244 //===----------------------------------------------------------------------===//
245 // CallOpaqueOp
246 //===----------------------------------------------------------------------===//
247 
249  // Callee must not be empty.
250  if (getCallee().empty())
251  return emitOpError("callee must not be empty");
252 
253  if (std::optional<ArrayAttr> argsAttr = getArgs()) {
254  for (Attribute arg : *argsAttr) {
255  auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
256  if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {
257  int64_t index = intAttr.getInt();
258  // Args with elements of type index must be in range
259  // [0..operands.size).
260  if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands())))
261  return emitOpError("index argument is out of range");
262 
263  // Args with elements of type ArrayAttr must have a type.
264  } else if (llvm::isa<ArrayAttr>(
265  arg) /*&& llvm::isa<NoneType>(arg.getType())*/) {
266  // FIXME: Array attributes never have types
267  return emitOpError("array argument has no type");
268  }
269  }
270  }
271 
272  if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
273  for (Attribute tArg : *templateArgsAttr) {
274  if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
275  return emitOpError("template argument has invalid type");
276  }
277  }
278 
279  if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {
280  return emitOpError() << "cannot return array type";
281  }
282 
283  return success();
284 }
285 
286 //===----------------------------------------------------------------------===//
287 // ConstantOp
288 //===----------------------------------------------------------------------===//
289 
291  Attribute value = getValueAttr();
292  if (failed(verifyInitializationAttribute(getOperation(), value)))
293  return failure();
294  if (auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) {
295  if (opaqueValue.getValue().empty())
296  return emitOpError() << "value must not be empty";
297  }
298  return success();
299 }
300 
301 OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }
302 
303 //===----------------------------------------------------------------------===//
304 // ExpressionOp
305 //===----------------------------------------------------------------------===//
306 
307 Operation *ExpressionOp::getRootOp() {
308  auto yieldOp = cast<YieldOp>(getBody()->getTerminator());
309  Value yieldedValue = yieldOp.getResult();
310  Operation *rootOp = yieldedValue.getDefiningOp();
311  assert(rootOp && "Yielded value not defined within expression");
312  return rootOp;
313 }
314 
316  Type resultType = getResult().getType();
317  Region &region = getRegion();
318 
319  Block &body = region.front();
320 
321  if (!body.mightHaveTerminator())
322  return emitOpError("must yield a value at termination");
323 
324  auto yield = cast<YieldOp>(body.getTerminator());
325  Value yieldResult = yield.getResult();
326 
327  if (!yieldResult)
328  return emitOpError("must yield a value at termination");
329 
330  Type yieldType = yieldResult.getType();
331 
332  if (resultType != yieldType)
333  return emitOpError("requires yielded type to match return type");
334 
335  for (Operation &op : region.front().without_terminator()) {
337  return emitOpError("contains an unsupported operation");
338  if (op.getNumResults() != 1)
339  return emitOpError("requires exactly one result for each operation");
340  if (!op.getResult(0).hasOneUse())
341  return emitOpError("requires exactly one use for each operation");
342  }
343 
344  return success();
345 }
346 
347 //===----------------------------------------------------------------------===//
348 // ForOp
349 //===----------------------------------------------------------------------===//
350 
351 void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
352  Value ub, Value step, BodyBuilderFn bodyBuilder) {
353  OpBuilder::InsertionGuard g(builder);
354  result.addOperands({lb, ub, step});
355  Type t = lb.getType();
356  Region *bodyRegion = result.addRegion();
357  Block *bodyBlock = builder.createBlock(bodyRegion);
358  bodyBlock->addArgument(t, result.location);
359 
360  // Create the default terminator if the builder is not provided.
361  if (!bodyBuilder) {
362  ForOp::ensureTerminator(*bodyRegion, builder, result.location);
363  } else {
364  OpBuilder::InsertionGuard guard(builder);
365  builder.setInsertionPointToStart(bodyBlock);
366  bodyBuilder(builder, result.location, bodyBlock->getArgument(0));
367  }
368 }
369 
370 void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}
371 
373  Builder &builder = parser.getBuilder();
374  Type type;
375 
376  OpAsmParser::Argument inductionVariable;
377  OpAsmParser::UnresolvedOperand lb, ub, step;
378 
379  // Parse the induction variable followed by '='.
380  if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
381  // Parse loop bounds.
382  parser.parseOperand(lb) || parser.parseKeyword("to") ||
383  parser.parseOperand(ub) || parser.parseKeyword("step") ||
384  parser.parseOperand(step))
385  return failure();
386 
387  // Parse the optional initial iteration arguments.
390  regionArgs.push_back(inductionVariable);
391 
392  // Parse optional type, else assume Index.
393  if (parser.parseOptionalColon())
394  type = builder.getIndexType();
395  else if (parser.parseType(type))
396  return failure();
397 
398  // Resolve input operands.
399  regionArgs.front().type = type;
400  if (parser.resolveOperand(lb, type, result.operands) ||
401  parser.resolveOperand(ub, type, result.operands) ||
402  parser.resolveOperand(step, type, result.operands))
403  return failure();
404 
405  // Parse the body region.
406  Region *body = result.addRegion();
407  if (parser.parseRegion(*body, regionArgs))
408  return failure();
409 
410  ForOp::ensureTerminator(*body, builder, result.location);
411 
412  // Parse the optional attribute list.
413  if (parser.parseOptionalAttrDict(result.attributes))
414  return failure();
415 
416  return success();
417 }
418 
419 void ForOp::print(OpAsmPrinter &p) {
420  p << " " << getInductionVar() << " = " << getLowerBound() << " to "
421  << getUpperBound() << " step " << getStep();
422 
423  p << ' ';
424  if (Type t = getInductionVar().getType(); !t.isIndex())
425  p << " : " << t << ' ';
426  p.printRegion(getRegion(),
427  /*printEntryBlockArgs=*/false,
428  /*printBlockTerminators=*/false);
429  p.printOptionalAttrDict((*this)->getAttrs());
430 }
431 
432 LogicalResult ForOp::verifyRegions() {
433  // Check that the body defines as single block argument for the induction
434  // variable.
435  if (getInductionVar().getType() != getLowerBound().getType())
436  return emitOpError(
437  "expected induction variable to be same type as bounds and step");
438 
439  return success();
440 }
441 
442 //===----------------------------------------------------------------------===//
443 // CallOp
444 //===----------------------------------------------------------------------===//
445 
446 LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
447  // Check that the callee attribute was specified.
448  auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");
449  if (!fnAttr)
450  return emitOpError("requires a 'callee' symbol reference attribute");
451  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
452  if (!fn)
453  return emitOpError() << "'" << fnAttr.getValue()
454  << "' does not reference a valid function";
455 
456  // Verify that the operand and result types match the callee.
457  auto fnType = fn.getFunctionType();
458  if (fnType.getNumInputs() != getNumOperands())
459  return emitOpError("incorrect number of operands for callee");
460 
461  for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)
462  if (getOperand(i).getType() != fnType.getInput(i))
463  return emitOpError("operand type mismatch: expected operand type ")
464  << fnType.getInput(i) << ", but provided "
465  << getOperand(i).getType() << " for operand number " << i;
466 
467  if (fnType.getNumResults() != getNumResults())
468  return emitOpError("incorrect number of results for callee");
469 
470  for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)
471  if (getResult(i).getType() != fnType.getResult(i)) {
472  auto diag = emitOpError("result type mismatch at index ") << i;
473  diag.attachNote() << " op result types: " << getResultTypes();
474  diag.attachNote() << "function result types: " << fnType.getResults();
475  return diag;
476  }
477 
478  return success();
479 }
480 
481 FunctionType CallOp::getCalleeType() {
482  return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
483 }
484 
485 //===----------------------------------------------------------------------===//
486 // DeclareFuncOp
487 //===----------------------------------------------------------------------===//
488 
490 DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
491  // Check that the sym_name attribute was specified.
492  auto fnAttr = getSymNameAttr();
493  if (!fnAttr)
494  return emitOpError("requires a 'sym_name' symbol reference attribute");
495  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
496  if (!fn)
497  return emitOpError() << "'" << fnAttr.getValue()
498  << "' does not reference a valid function";
499 
500  return success();
501 }
502 
503 //===----------------------------------------------------------------------===//
504 // FuncOp
505 //===----------------------------------------------------------------------===//
506 
507 void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
508  FunctionType type, ArrayRef<NamedAttribute> attrs,
509  ArrayRef<DictionaryAttr> argAttrs) {
510  state.addAttribute(SymbolTable::getSymbolAttrName(),
511  builder.getStringAttr(name));
512  state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
513  state.attributes.append(attrs.begin(), attrs.end());
514  state.addRegion();
515 
516  if (argAttrs.empty())
517  return;
518  assert(type.getNumInputs() == argAttrs.size());
520  builder, state, argAttrs, /*resultAttrs=*/std::nullopt,
521  getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
522 }
523 
525  auto buildFuncType =
526  [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
528  std::string &) { return builder.getFunctionType(argTypes, results); };
529 
531  parser, result, /*allowVariadic=*/false,
532  getFunctionTypeAttrName(result.name), buildFuncType,
533  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
534 }
535 
536 void FuncOp::print(OpAsmPrinter &p) {
538  p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
539  getArgAttrsAttrName(), getResAttrsAttrName());
540 }
541 
543  if (getNumResults() > 1)
544  return emitOpError("requires zero or exactly one result, but has ")
545  << getNumResults();
546 
547  if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
548  return emitOpError("cannot return array type");
549 
550  return success();
551 }
552 
553 //===----------------------------------------------------------------------===//
554 // ReturnOp
555 //===----------------------------------------------------------------------===//
556 
558  auto function = cast<FuncOp>((*this)->getParentOp());
559 
560  // The operand number and types must match the function signature.
561  if (getNumOperands() != function.getNumResults())
562  return emitOpError("has ")
563  << getNumOperands() << " operands, but enclosing function (@"
564  << function.getName() << ") returns " << function.getNumResults();
565 
566  if (function.getNumResults() == 1)
567  if (getOperand().getType() != function.getResultTypes()[0])
568  return emitError() << "type of the return operand ("
569  << getOperand().getType()
570  << ") doesn't match function result type ("
571  << function.getResultTypes()[0] << ")"
572  << " in function @" << function.getName();
573  return success();
574 }
575 
576 //===----------------------------------------------------------------------===//
577 // IfOp
578 //===----------------------------------------------------------------------===//
579 
580 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
581  bool addThenBlock, bool addElseBlock) {
582  assert((!addElseBlock || addThenBlock) &&
583  "must not create else block w/o then block");
584  result.addOperands(cond);
585 
586  // Add regions and blocks.
587  OpBuilder::InsertionGuard guard(builder);
588  Region *thenRegion = result.addRegion();
589  if (addThenBlock)
590  builder.createBlock(thenRegion);
591  Region *elseRegion = result.addRegion();
592  if (addElseBlock)
593  builder.createBlock(elseRegion);
594 }
595 
596 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
597  bool withElseRegion) {
598  result.addOperands(cond);
599 
600  // Build then region.
601  OpBuilder::InsertionGuard guard(builder);
602  Region *thenRegion = result.addRegion();
603  builder.createBlock(thenRegion);
604 
605  // Build else region.
606  Region *elseRegion = result.addRegion();
607  if (withElseRegion) {
608  builder.createBlock(elseRegion);
609  }
610 }
611 
612 void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
613  function_ref<void(OpBuilder &, Location)> thenBuilder,
614  function_ref<void(OpBuilder &, Location)> elseBuilder) {
615  assert(thenBuilder && "the builder callback for 'then' must be present");
616  result.addOperands(cond);
617 
618  // Build then region.
619  OpBuilder::InsertionGuard guard(builder);
620  Region *thenRegion = result.addRegion();
621  builder.createBlock(thenRegion);
622  thenBuilder(builder, result.location);
623 
624  // Build else region.
625  Region *elseRegion = result.addRegion();
626  if (elseBuilder) {
627  builder.createBlock(elseRegion);
628  elseBuilder(builder, result.location);
629  }
630 }
631 
633  // Create the regions for 'then'.
634  result.regions.reserve(2);
635  Region *thenRegion = result.addRegion();
636  Region *elseRegion = result.addRegion();
637 
638  Builder &builder = parser.getBuilder();
640  Type i1Type = builder.getIntegerType(1);
641  if (parser.parseOperand(cond) ||
642  parser.resolveOperand(cond, i1Type, result.operands))
643  return failure();
644  // Parse the 'then' region.
645  if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))
646  return failure();
647  IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
648 
649  // If we find an 'else' keyword then parse the 'else' region.
650  if (!parser.parseOptionalKeyword("else")) {
651  if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))
652  return failure();
653  IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
654  }
655 
656  // Parse the optional attribute list.
657  if (parser.parseOptionalAttrDict(result.attributes))
658  return failure();
659  return success();
660 }
661 
662 void IfOp::print(OpAsmPrinter &p) {
663  bool printBlockTerminators = false;
664 
665  p << " " << getCondition();
666  p << ' ';
667  p.printRegion(getThenRegion(),
668  /*printEntryBlockArgs=*/false,
669  /*printBlockTerminators=*/printBlockTerminators);
670 
671  // Print the 'else' regions if it exists and has a block.
672  Region &elseRegion = getElseRegion();
673  if (!elseRegion.empty()) {
674  p << " else ";
675  p.printRegion(elseRegion,
676  /*printEntryBlockArgs=*/false,
677  /*printBlockTerminators=*/printBlockTerminators);
678  }
679 
680  p.printOptionalAttrDict((*this)->getAttrs());
681 }
682 
683 /// Given the region at `index`, or the parent operation if `index` is None,
684 /// return the successor regions. These are the regions that may be selected
685 /// during the flow of control. `operands` is a set of optional attributes that
686 /// correspond to a constant value for each operand, or null if that operand is
687 /// not a constant.
688 void IfOp::getSuccessorRegions(RegionBranchPoint point,
690  // The `then` and the `else` region branch back to the parent operation.
691  if (!point.isParent()) {
692  regions.push_back(RegionSuccessor());
693  return;
694  }
695 
696  regions.push_back(RegionSuccessor(&getThenRegion()));
697 
698  // Don't consider the else region if it is empty.
699  Region *elseRegion = &this->getElseRegion();
700  if (elseRegion->empty())
701  regions.push_back(RegionSuccessor());
702  else
703  regions.push_back(RegionSuccessor(elseRegion));
704 }
705 
706 void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,
708  FoldAdaptor adaptor(operands, *this);
709  auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
710  if (!boolAttr || boolAttr.getValue())
711  regions.emplace_back(&getThenRegion());
712 
713  // If the else region is empty, execution continues after the parent op.
714  if (!boolAttr || !boolAttr.getValue()) {
715  if (!getElseRegion().empty())
716  regions.emplace_back(&getElseRegion());
717  else
718  regions.emplace_back();
719  }
720 }
721 
722 void IfOp::getRegionInvocationBounds(
723  ArrayRef<Attribute> operands,
724  SmallVectorImpl<InvocationBounds> &invocationBounds) {
725  if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
726  // If the condition is known, then one region is known to be executed once
727  // and the other zero times.
728  invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
729  invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
730  } else {
731  // Non-constant condition. Each region may be executed 0 or 1 times.
732  invocationBounds.assign(2, {0, 1});
733  }
734 }
735 
736 //===----------------------------------------------------------------------===//
737 // IncludeOp
738 //===----------------------------------------------------------------------===//
739 
741  bool standardInclude = getIsStandardInclude();
742 
743  p << " ";
744  if (standardInclude)
745  p << "<";
746  p << "\"" << getInclude() << "\"";
747  if (standardInclude)
748  p << ">";
749 }
750 
752  bool standardInclude = !parser.parseOptionalLess();
753 
754  StringAttr include;
755  OptionalParseResult includeParseResult =
756  parser.parseOptionalAttribute(include, "include", result.attributes);
757  if (!includeParseResult.has_value())
758  return parser.emitError(parser.getNameLoc()) << "expected string attribute";
759 
760  if (standardInclude && parser.parseOptionalGreater())
761  return parser.emitError(parser.getNameLoc())
762  << "expected trailing '>' for standard include";
763 
764  if (standardInclude)
765  result.addAttribute("is_standard_include",
766  UnitAttr::get(parser.getContext()));
767 
768  return success();
769 }
770 
771 //===----------------------------------------------------------------------===//
772 // LiteralOp
773 //===----------------------------------------------------------------------===//
774 
775 /// The literal op requires a non-empty value.
777  if (getValue().empty())
778  return emitOpError() << "value must not be empty";
779  return success();
780 }
781 //===----------------------------------------------------------------------===//
782 // SubOp
783 //===----------------------------------------------------------------------===//
784 
786  Type lhsType = getLhs().getType();
787  Type rhsType = getRhs().getType();
788  Type resultType = getResult().getType();
789 
790  if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
791  return emitOpError("rhs can only be a pointer if lhs is a pointer");
792 
793  if (isa<emitc::PointerType>(lhsType) &&
794  !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
795  return emitOpError("requires that rhs is an integer, pointer or of opaque "
796  "type if lhs is a pointer");
797 
798  if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
799  !isa<IntegerType, emitc::OpaqueType>(resultType))
800  return emitOpError("requires that the result is an integer or of opaque "
801  "type if lhs and rhs are pointers");
802  return success();
803 }
804 
805 //===----------------------------------------------------------------------===//
806 // VariableOp
807 //===----------------------------------------------------------------------===//
808 
810  return verifyInitializationAttribute(getOperation(), getValueAttr());
811 }
812 
813 //===----------------------------------------------------------------------===//
814 // YieldOp
815 //===----------------------------------------------------------------------===//
816 
818  Value result = getResult();
819  Operation *containingOp = getOperation()->getParentOp();
820 
821  if (result && containingOp->getNumResults() != 1)
822  return emitOpError() << "yields a value not returned by parent";
823 
824  if (!result && containingOp->getNumResults() != 0)
825  return emitOpError() << "does not yield a value to be returned by parent";
826 
827  return success();
828 }
829 
830 //===----------------------------------------------------------------------===//
831 // SubscriptOp
832 //===----------------------------------------------------------------------===//
833 
835  // Checks for array operand.
836  if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {
837  // Check number of indices.
838  if (getIndices().size() != (size_t)arrayType.getRank()) {
839  return emitOpError() << "on array operand requires number of indices ("
840  << getIndices().size()
841  << ") to match the rank of the array type ("
842  << arrayType.getRank() << ")";
843  }
844  // Check types of index operands.
845  for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {
846  Type type = getIndices()[i].getType();
847  if (!isIntegerIndexOrOpaqueType(type)) {
848  return emitOpError() << "on array operand requires index operand " << i
849  << " to be integer-like, but got " << type;
850  }
851  }
852  // Check element type.
853  Type elementType = arrayType.getElementType();
854  if (elementType != getType()) {
855  return emitOpError() << "on array operand requires element type ("
856  << elementType << ") and result type (" << getType()
857  << ") to match";
858  }
859  return success();
860  }
861 
862  // Checks for pointer operand.
863  if (auto pointerType =
864  llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {
865  // Check number of indices.
866  if (getIndices().size() != 1) {
867  return emitOpError()
868  << "on pointer operand requires one index operand, but got "
869  << getIndices().size();
870  }
871  // Check types of index operand.
872  Type type = getIndices()[0].getType();
873  if (!isIntegerIndexOrOpaqueType(type)) {
874  return emitOpError() << "on pointer operand requires index operand to be "
875  "integer-like, but got "
876  << type;
877  }
878  // Check pointee type.
879  Type pointeeType = pointerType.getPointee();
880  if (pointeeType != getType()) {
881  return emitOpError() << "on pointer operand requires pointee type ("
882  << pointeeType << ") and result type (" << getType()
883  << ") to match";
884  }
885  return success();
886  }
887 
888  // The operand has opaque type, so we can't assume anything about the number
889  // or types of index operands.
890  return success();
891 }
892 
893 //===----------------------------------------------------------------------===//
894 // EmitC Enums
895 //===----------------------------------------------------------------------===//
896 
897 #include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
898 
899 //===----------------------------------------------------------------------===//
900 // EmitC Attributes
901 //===----------------------------------------------------------------------===//
902 
903 #define GET_ATTRDEF_CLASSES
904 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
905 
906 //===----------------------------------------------------------------------===//
907 // EmitC Types
908 //===----------------------------------------------------------------------===//
909 
910 #define GET_TYPEDEF_CLASSES
911 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
912 
913 //===----------------------------------------------------------------------===//
914 // ArrayType
915 //===----------------------------------------------------------------------===//
916 
918  if (parser.parseLess())
919  return Type();
920 
921  SmallVector<int64_t, 4> dimensions;
922  if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,
923  /*withTrailingX=*/true))
924  return Type();
925  // Parse the element type.
926  auto typeLoc = parser.getCurrentLocation();
927  Type elementType;
928  if (parser.parseType(elementType))
929  return Type();
930 
931  // Check that array is formed from allowed types.
932  if (!isValidElementType(elementType))
933  return parser.emitError(typeLoc, "invalid array element type"), Type();
934  if (parser.parseGreater())
935  return Type();
936  return parser.getChecked<ArrayType>(dimensions, elementType);
937 }
938 
939 void emitc::ArrayType::print(AsmPrinter &printer) const {
940  printer << "<";
941  for (int64_t dim : getShape()) {
942  printer << dim << 'x';
943  }
944  printer.printType(getElementType());
945  printer << ">";
946 }
947 
950  ::llvm::ArrayRef<int64_t> shape, Type elementType) {
951  if (shape.empty())
952  return emitError() << "shape must not be empty";
953 
954  for (int64_t dim : shape) {
955  if (dim <= 0)
956  return emitError() << "dimensions must have positive size";
957  }
958 
959  if (!elementType)
960  return emitError() << "element type must not be none";
961 
962  if (!isValidElementType(elementType))
963  return emitError() << "invalid array element type";
964 
965  return success();
966 }
967 
968 emitc::ArrayType
969 emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
970  Type elementType) const {
971  if (!shape)
972  return emitc::ArrayType::get(getShape(), elementType);
973  return emitc::ArrayType::get(*shape, elementType);
974 }
975 
976 //===----------------------------------------------------------------------===//
977 // OpaqueType
978 //===----------------------------------------------------------------------===//
979 
982  llvm::StringRef value) {
983  if (value.empty()) {
984  return emitError() << "expected non empty string in !emitc.opaque type";
985  }
986  if (value.back() == '*') {
987  return emitError() << "pointer not allowed as outer type with "
988  "!emitc.opaque, use !emitc.ptr instead";
989  }
990  return success();
991 }
992 
993 //===----------------------------------------------------------------------===//
994 // GlobalOp
995 //===----------------------------------------------------------------------===//
997  TypeAttr type,
998  Attribute initialValue) {
999  p << type;
1000  if (initialValue) {
1001  p << " = ";
1002  p.printAttributeWithoutType(initialValue);
1003  }
1004 }
1005 
1007  if (auto array = llvm::dyn_cast<ArrayType>(type))
1008  return RankedTensorType::get(array.getShape(), array.getElementType());
1009  return type;
1010 }
1011 
1012 static ParseResult
1014  Attribute &initialValue) {
1015  Type type;
1016  if (parser.parseType(type))
1017  return failure();
1018 
1019  typeAttr = TypeAttr::get(type);
1020 
1021  if (parser.parseOptionalEqual())
1022  return success();
1023 
1024  if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))
1025  return failure();
1026 
1027  if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1028  initialValue))
1029  return parser.emitError(parser.getNameLoc())
1030  << "initial value should be a integer, float, elements or opaque "
1031  "attribute";
1032  return success();
1033 }
1034 
1036  if (!isSupportedEmitCType(getType())) {
1037  return emitOpError("expected valid emitc type");
1038  }
1039  if (getInitialValue().has_value()) {
1040  Attribute initValue = getInitialValue().value();
1041  // Check that the type of the initial value is compatible with the type of
1042  // the global variable.
1043  if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1044  auto arrayType = llvm::dyn_cast<ArrayType>(getType());
1045  if (!arrayType)
1046  return emitOpError("expected array type, but got ") << getType();
1047 
1048  Type initType = elementsAttr.getType();
1049  Type tensorType = getInitializerTypeForGlobal(getType());
1050  if (initType != tensorType) {
1051  return emitOpError("initial value expected to be of type ")
1052  << getType() << ", but was of type " << initType;
1053  }
1054  } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1055  if (intAttr.getType() != getType()) {
1056  return emitOpError("initial value expected to be of type ")
1057  << getType() << ", but was of type " << intAttr.getType();
1058  }
1059  } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1060  if (floatAttr.getType() != getType()) {
1061  return emitOpError("initial value expected to be of type ")
1062  << getType() << ", but was of type " << floatAttr.getType();
1063  }
1064  } else if (!isa<emitc::OpaqueAttr>(initValue)) {
1065  return emitOpError("initial value should be a integer, float, elements "
1066  "or opaque attribute, but got ")
1067  << initValue;
1068  }
1069  }
1070  if (getStaticSpecifier() && getExternSpecifier()) {
1071  return emitOpError("cannot have both static and extern specifiers");
1072  }
1073  return success();
1074 }
1075 
1076 //===----------------------------------------------------------------------===//
1077 // GetGlobalOp
1078 //===----------------------------------------------------------------------===//
1079 
1081 GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1082  // Verify that the type matches the type of the global variable.
1083  auto global =
1084  symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1085  if (!global)
1086  return emitOpError("'")
1087  << getName() << "' does not reference a valid emitc.global";
1088 
1089  Type resultType = getResult().getType();
1090  if (global.getType() != resultType)
1091  return emitOpError("result type ")
1092  << resultType << " does not match type " << global.getType()
1093  << " of the global @" << getName();
1094  return success();
1095 }
1096 
1097 //===----------------------------------------------------------------------===//
1098 // TableGen'd op method definitions
1099 //===----------------------------------------------------------------------===//
1100 
1101 #define GET_OP_CLASSES
1102 #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:720
static std::optional< int64_t > getLowerBound(Value iv)
Gets the constant lower bound on an iv.
Definition: AffineOps.cpp:712
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:136
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition: EmitC.cpp:1013
static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, TypeAttr type, Attribute initialValue)
Definition: EmitC.cpp:996
static Type getInitializerTypeForGlobal(Type type)
Definition: EmitC.cpp:1006
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:216
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: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.
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:31
BlockArgument getArgument(unsigned i)
Definition: Block.h:127
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:243
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:152
bool mightHaveTerminator()
Check whether this block might have a terminator.
Definition: Block.cpp:249
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
Definition: Block.h:207
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition: Builders.cpp:96
IntegerType getIntegerType(unsigned width)
Definition: Builders.cpp:87
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:269
IndexType getIndexType()
Definition: Builders.cpp:71
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:308
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
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 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:350
This class helps build Operations.
Definition: Builders.h:209
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition: Builders.h:433
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:437
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:464
This class represents a single result from folding an operation.
Definition: OpDefinition.h:268
type_range getType() const
Definition: ValueRange.cpp:30
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:745
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
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:399
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 success/failure for parsing-like operations that find it important to chain tog...
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 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:36
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:56
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:129
bool hasOneUse() const
Returns true if this value has exactly one use.
Definition: Value.h:215
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
A named class for passing around the variadic flag.
void buildTerminatedBody(OpBuilder &builder, Location loc)
Default callback for builders of ops carrying a region.
Definition: EmitC.cpp:57
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:129
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 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,...
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
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:305
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
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:421
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
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.