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