MLIR 24.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"
14#include "mlir/IR/IRMapping.h"
15#include "mlir/IR/Types.h"
17#include "mlir/Support/LLVM.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/Support/Casting.h"
21
22using namespace mlir;
23using namespace mlir::emitc;
24
25#include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc"
26
27//===----------------------------------------------------------------------===//
28// EmitCDialect
29//===----------------------------------------------------------------------===//
30
31void EmitCDialect::initialize() {
32 addOperations<
33#define GET_OP_LIST
34#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
35 >();
36 addTypes<
37#define GET_TYPEDEF_LIST
38#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
39 >();
40 addAttributes<
41#define GET_ATTRDEF_LIST
42#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
43 >();
44}
45
46/// Materialize a single constant operation from a given attribute value with
47/// the desired resultant type.
48Operation *EmitCDialect::materializeConstant(OpBuilder &builder,
49 Attribute value, Type type,
50 Location loc) {
51 return emitc::ConstantOp::create(builder, loc, type, value);
52}
53
54/// Default callback for builders of ops carrying a region. Inserts a yield
55/// without arguments.
57 emitc::YieldOp::create(builder, loc);
58}
59
61 if (llvm::isa<emitc::OpaqueType>(type))
62 return true;
63 if (auto ptrType = llvm::dyn_cast<emitc::PointerType>(type))
64 return isSupportedEmitCType(ptrType.getPointee());
65 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(type)) {
66 auto elemType = arrayType.getElementType();
67 return !llvm::isa<emitc::ArrayType>(elemType) &&
68 isSupportedEmitCType(elemType);
69 }
70 if (type.isIndex() || emitc::isPointerWideType(type))
71 return true;
72 if (llvm::isa<IntegerType>(type))
73 return isSupportedIntegerType(type);
74 if (llvm::isa<FloatType>(type))
75 return isSupportedFloatType(type);
76 if (auto tensorType = llvm::dyn_cast<TensorType>(type)) {
77 if (!tensorType.hasStaticShape()) {
78 return false;
79 }
80 auto elemType = tensorType.getElementType();
81 if (llvm::isa<emitc::ArrayType>(elemType)) {
82 return false;
83 }
84 return isSupportedEmitCType(elemType);
85 }
86 if (auto tupleType = llvm::dyn_cast<TupleType>(type)) {
87 return llvm::all_of(tupleType.getTypes(), [](Type type) {
88 return !llvm::isa<emitc::ArrayType>(type) && isSupportedEmitCType(type);
89 });
90 }
91 return false;
92}
93
95 if (auto intType = llvm::dyn_cast<IntegerType>(type)) {
96 switch (intType.getWidth()) {
97 case 1:
98 case 8:
99 case 16:
100 case 32:
101 case 64:
102 return true;
103 default:
104 return false;
105 }
106 }
107 return false;
108}
109
111 return llvm::isa<IndexType, emitc::OpaqueType>(type) ||
113}
114
116 if (auto floatType = llvm::dyn_cast<FloatType>(type)) {
117 switch (floatType.getWidth()) {
118 case 16:
119 return llvm::isa<Float16Type, BFloat16Type>(type);
120 case 32:
121 case 64:
122 return true;
123 default:
124 return false;
125 }
126 }
127 return false;
128}
129
131 return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>(
132 type);
133}
134
136 return llvm::isa<IndexType>(type) || isPointerWideType(type) ||
138 isa<emitc::PointerType>(type);
139}
140
141/// Check that the type of the initial value is compatible with the operations
142/// result type.
144 Attribute value) {
145 assert(op->getNumResults() == 1 && "operation must have 1 result");
146
147 if (llvm::isa<emitc::OpaqueAttr>(value))
148 return success();
149
150 if (llvm::isa<StringAttr>(value))
151 return op->emitOpError()
152 << "string attributes are not supported, use #emitc.opaque instead";
153
154 Type resultType = op->getResult(0).getType();
155 if (auto lType = dyn_cast<LValueType>(resultType))
156 resultType = lType.getValueType();
157 Type attrType = cast<TypedAttr>(value).getType();
158
159 if (isPointerWideType(resultType) && attrType.isIndex())
160 return success();
161
162 if (resultType != attrType)
163 return op->emitOpError()
164 << "requires attribute to either be an #emitc.opaque attribute or "
165 "it's type ("
166 << attrType << ") to match the op's result type (" << resultType
167 << ")";
168
169 return success();
170}
171
172/// Parse a format string and return a list of its parts.
173/// A part is either a StringRef that has to be printed as-is, or
174/// a Placeholder which requires printing the next operand of the VerbatimOp.
175/// In the format string, all `{}` are replaced by Placeholders, except if the
176/// `{` is escaped by `{{` - then it doesn't start a placeholder.
177template <class ArgType>
178FailureOr<SmallVector<ReplacementItem>> parseFormatString(
179 StringRef toParse, ArgType fmtArgs,
182
183 // If there are not operands, the format string is not interpreted.
184 if (fmtArgs.empty()) {
185 items.push_back(toParse);
186 return items;
187 }
188
189 while (!toParse.empty()) {
190 size_t idx = toParse.find('{');
191 if (idx == StringRef::npos) {
192 // No '{'
193 items.push_back(toParse);
194 break;
195 }
196 if (idx > 0) {
197 // Take all chars excluding the '{'.
198 items.push_back(toParse.take_front(idx));
199 toParse = toParse.drop_front(idx);
200 continue;
201 }
202 if (toParse.size() < 2) {
203 return emitError() << "expected '}' after unescaped '{' at end of string";
204 }
205 // toParse contains at least two characters and starts with `{`.
206 char nextChar = toParse[1];
207 if (nextChar == '{') {
208 // Double '{{' -> '{' (escaping).
209 items.push_back(toParse.take_front(1));
210 toParse = toParse.drop_front(2);
211 continue;
212 }
213 if (nextChar == '}') {
214 items.push_back(Placeholder{});
215 toParse = toParse.drop_front(2);
216 continue;
217 }
218
219 if (emitError) {
220 return emitError() << "expected '}' after unescaped '{'";
221 }
222 return failure();
223 }
224 return items;
225}
226
227//===----------------------------------------------------------------------===//
228// AddressOfOp
229//===----------------------------------------------------------------------===//
230
231LogicalResult AddressOfOp::verify() {
232 emitc::LValueType referenceType = getReference().getType();
233 emitc::PointerType resultType = getResult().getType();
234
235 if (referenceType.getValueType() != resultType.getPointee())
236 return emitOpError("requires result to be a pointer to the type "
237 "referenced by operand");
238
239 return success();
240}
241
242//===----------------------------------------------------------------------===//
243// AddOp
244//===----------------------------------------------------------------------===//
245
246LogicalResult AddOp::verify() {
247 Type lhsType = getLhs().getType();
248 Type rhsType = getRhs().getType();
249
250 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType))
251 return emitOpError("requires that at most one operand is a pointer");
252
253 if ((isa<emitc::PointerType>(lhsType) &&
254 !isa<IntegerType, emitc::OpaqueType>(rhsType)) ||
255 (isa<emitc::PointerType>(rhsType) &&
256 !isa<IntegerType, emitc::OpaqueType>(lhsType)))
257 return emitOpError("requires that one operand is an integer or of opaque "
258 "type if the other is a pointer");
259
260 return success();
261}
262
263//===----------------------------------------------------------------------===//
264// Assignment operations
265//===----------------------------------------------------------------------===//
266
267template <typename AssignmentOp>
268static LogicalResult verifyAssignmentOp(AssignmentOp op) {
269 TypedValue<emitc::LValueType> variable = op.getVar();
270
271 if (!variable.getDefiningOp())
272 return op.emitOpError() << "cannot assign to block argument";
273
274 Type valueType = op.getValue().getType();
275 Type variableType = variable.getType().getValueType();
276 if (variableType != valueType)
277 return op.emitOpError() << "requires value's type (" << valueType
278 << ") to match variable's type (" << variableType
279 << ")\n variable: " << variable
280 << "\n value: " << op.getValue() << "\n";
281 return success();
282}
283
284LogicalResult emitc::AssignOp::verify() { return verifyAssignmentOp(*this); }
285
286LogicalResult emitc::AddAssignOp::verify() { return verifyAssignmentOp(*this); }
287
288LogicalResult emitc::SubAssignOp::verify() { return verifyAssignmentOp(*this); }
289
290LogicalResult emitc::MulAssignOp::verify() { return verifyAssignmentOp(*this); }
291
292LogicalResult emitc::DivAssignOp::verify() { return verifyAssignmentOp(*this); }
293
294LogicalResult emitc::RemAssignOp::verify() { return verifyAssignmentOp(*this); }
295
296//===----------------------------------------------------------------------===//
297// CastOp
298//===----------------------------------------------------------------------===//
299
300bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
301 Type input = inputs.front(), output = outputs.front();
302
303 if (auto arrayType = dyn_cast<emitc::ArrayType>(input)) {
304 if (auto pointerType = dyn_cast<emitc::PointerType>(output)) {
305 return (arrayType.getElementType() == pointerType.getPointee()) &&
306 arrayType.getShape().size() == 1 && arrayType.getShape()[0] >= 1;
307 }
308 return false;
309 }
310
311 return (
313 emitc::isSupportedFloatType(input) || isa<emitc::PointerType>(input)) &&
315 emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output)));
316}
317
318Speculation::Speculatability emitc::CastOp::getSpeculatability() {
320}
321
322void emitc::CastOp::getEffects(
324 if (getPure())
325 return;
326
327 effects.emplace_back(MemoryEffects::Read::get());
328 effects.emplace_back(MemoryEffects::Write::get());
329}
330
331//===----------------------------------------------------------------------===//
332// CallOpaqueOp
333//===----------------------------------------------------------------------===//
334
335static LogicalResult
336verifyOpaqueCallCommon(Operation *op, StringRef callee,
337 std::optional<ArrayAttr> args,
338 std::optional<ArrayAttr> templateArgs,
339 TypeRange resultTypes, size_t numArgsOperands) {
340 // Callee must not be empty.
341 if (callee.empty())
342 return op->emitOpError("callee must not be empty");
343
344 if (args) {
345 for (Attribute arg : *args) {
346 auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
347 if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {
348 int64_t index = intAttr.getInt();
349 // Args with elements of type index must be in range
350 // [0..numArgsOperands).
351 if ((index < 0) || (index >= static_cast<int64_t>(numArgsOperands)))
352 return op->emitOpError("index argument is out of range");
353
354 } else if (llvm::isa<ArrayAttr>(arg)) {
355 return op->emitOpError("array argument has no type");
356 }
357 }
358 }
359
360 if (templateArgs) {
361 for (Attribute tArg : *templateArgs) {
362 if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
363 return op->emitOpError("template argument has invalid type");
364 }
365 }
366
367 if (llvm::any_of(resultTypes, llvm::IsaPred<ArrayType>)) {
368 return op->emitOpError() << "cannot return array type";
369 }
370
371 return success();
372}
373
374LogicalResult emitc::CallOpaqueOp::verify() {
375 return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
376 getTemplateArgs(), getResultTypes(),
378}
379
380LogicalResult emitc::MemberCallOpaqueOp::verify() {
381 return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
382 getTemplateArgs(), getResultTypes(),
383 getArgOperands().size());
384}
385
386//===----------------------------------------------------------------------===//
387// ConstantOp
388//===----------------------------------------------------------------------===//
389
390LogicalResult emitc::ConstantOp::verify() {
391 Attribute value = getValueAttr();
392 if (failed(verifyInitializationAttribute(getOperation(), value)))
393 return failure();
394 if (auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) {
395 if (opaqueValue.getValue().empty())
396 return emitOpError() << "value must not be empty";
397 }
398 return success();
399}
400
401OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }
402
403//===----------------------------------------------------------------------===//
404// DereferenceOp
405//===----------------------------------------------------------------------===//
406
407LogicalResult DereferenceOp::verify() {
408 emitc::PointerType pointerType = getPointer().getType();
409
410 if (pointerType.getPointee() != getResult().getType().getValueType())
411 return emitOpError("requires result to be an lvalue of the type "
412 "pointed to by operand");
413
414 return success();
415}
416
417//===----------------------------------------------------------------------===//
418// ExpressionOp
419//===----------------------------------------------------------------------===//
420
421namespace {
422
423struct RemoveRecurringExpressionOperands
424 : public OpRewritePattern<ExpressionOp> {
425 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
426 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
427 PatternRewriter &rewriter) const override {
428 SetVector<Value> uniqueOperands;
429 DenseMap<Value, int> firstIndexOf;
430
431 // Collect duplicate operands and prepare to remove excessive copies.
432 for (auto [i, operand] : llvm::enumerate(expressionOp.getDefs())) {
433 if (uniqueOperands.contains(operand))
434 continue;
435 uniqueOperands.insert(operand);
436 firstIndexOf[operand] = i;
437 }
438
439 // If every operand is unique, bail out.
440 if (uniqueOperands.size() == expressionOp.getDefs().size())
441 return failure();
442
443 // Create a new expression with unique operands.
444 rewriter.setInsertionPointAfter(expressionOp);
445 auto uniqueExpression = emitc::ExpressionOp::create(
446 rewriter, expressionOp.getLoc(), expressionOp.getResult().getType(),
447 uniqueOperands.getArrayRef(), expressionOp.getDoNotInline());
448 Block &uniqueExpressionBody = uniqueExpression.createBody();
449
450 // Map each original block arguments to the unique block argument taking
451 // the same operand.
452 IRMapping mapper;
453 Block *expressionBody = expressionOp.getBody();
454 for (auto [operand, arg] :
455 llvm::zip(expressionOp.getOperands(), expressionBody->getArguments()))
456 mapper.map(arg, uniqueExpressionBody.getArgument(firstIndexOf[operand]));
457
458 rewriter.setInsertionPointToStart(&uniqueExpressionBody);
459 for (Operation &opToClone : *expressionOp.getBody())
460 rewriter.clone(opToClone, mapper);
461
462 // Complete the rewrite.
463 rewriter.replaceOp(expressionOp, uniqueExpression);
464
465 return success();
466 }
467};
468
469/// If an ExpressionOp body yields a block argument directly (no root op),
470/// this means a contained op was folded away (e.g., an identity cast whose
471/// in/out types match). Canonicalize by replacing the expression with the
472/// corresponding operand value.
473struct FoldTrivialExpressionOp : public OpRewritePattern<ExpressionOp> {
474 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
475 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
476 PatternRewriter &rewriter) const override {
477 auto yieldOp = cast<YieldOp>(expressionOp.getBody()->getTerminator());
478 Value yieldedValue = yieldOp.getResult();
479 auto blockArg = dyn_cast_if_present<BlockArgument>(yieldedValue);
480 if (!blockArg)
481 return failure();
482 rewriter.replaceOp(expressionOp,
483 expressionOp.getOperand(blockArg.getArgNumber()));
484 return success();
485 }
486};
487
488} // namespace
489
490void ExpressionOp::getCanonicalizationPatterns(RewritePatternSet &results,
491 MLIRContext *context) {
492 results.add<RemoveRecurringExpressionOperands, FoldTrivialExpressionOp>(
493 context);
494}
495
496ParseResult ExpressionOp::parse(OpAsmParser &parser, OperationState &result) {
498 if (parser.parseOperandList(operands))
499 return parser.emitError(parser.getCurrentLocation()) << "expected operands";
500 if (succeeded(parser.parseOptionalKeyword("noinline")))
501 result.addAttribute(ExpressionOp::getDoNotInlineAttrName(result.name),
502 parser.getBuilder().getUnitAttr());
503 Type type;
504 if (parser.parseColonType(type))
505 return parser.emitError(parser.getCurrentLocation(),
506 "expected function type");
507 auto fnType = llvm::dyn_cast<FunctionType>(type);
508 if (!fnType)
509 return parser.emitError(parser.getCurrentLocation(),
510 "expected function type");
511 if (parser.resolveOperands(operands, fnType.getInputs(),
512 parser.getCurrentLocation(), result.operands))
513 return failure();
514 if (fnType.getNumResults() != 1)
515 return parser.emitError(parser.getCurrentLocation(),
516 "expected single return type");
517 result.addTypes(fnType.getResults());
518 Region *body = result.addRegion();
519 DenseSet<Value> uniqueOperands(result.operands.begin(),
520 result.operands.end());
521 bool enableNameShadowing = uniqueOperands.size() == result.operands.size();
523 if (enableNameShadowing) {
524 for (auto [unresolvedOperand, operandType] :
525 llvm::zip(operands, fnType.getInputs())) {
526 OpAsmParser::Argument argInfo;
527 argInfo.ssaName = unresolvedOperand;
528 argInfo.type = operandType;
529 argsInfo.push_back(argInfo);
530 }
531 }
532 SMLoc beforeRegionLoc = parser.getCurrentLocation();
533 if (parser.parseRegion(*body, argsInfo, enableNameShadowing))
534 return failure();
535 if (!enableNameShadowing) {
536 if (body->front().getArguments().size() < result.operands.size()) {
537 return parser.emitError(
538 beforeRegionLoc, "with recurring operands expected block arguments");
539 }
540 }
541 return success();
542}
543
544void emitc::ExpressionOp::print(OpAsmPrinter &p) {
545 p << ' ';
546 auto operands = getDefs();
547 p.printOperands(operands);
548 p << " : ";
549 p.printFunctionalType(getOperation());
550 DenseSet<Value> uniqueOperands(operands.begin(), operands.end());
551 bool printEntryBlockArgs = true;
552 if (uniqueOperands.size() == operands.size()) {
553 p.shadowRegionArgs(getRegion(), getDefs());
554 printEntryBlockArgs = false;
555 }
556 p << ' ';
557 p.printRegion(getRegion(), printEntryBlockArgs);
558}
559
560Operation *ExpressionOp::getRootOp() {
561 auto yieldOp = cast<YieldOp>(getBody()->getTerminator());
562 Value yieldedValue = yieldOp.getResult();
563 return yieldedValue.getDefiningOp();
564}
565
566LogicalResult ExpressionOp::verify() {
567 Type resultType = getResult().getType();
568 Region &region = getRegion();
569
570 Block &body = region.front();
571
572 if (!body.mightHaveTerminator())
573 return emitOpError("must yield a value at termination");
574
575 auto yield = cast<YieldOp>(body.getTerminator());
576 Value yieldResult = yield.getResult();
577
578 if (!yieldResult)
579 return emitOpError("must yield a value at termination");
580
581 Operation *rootOp = yieldResult.getDefiningOp();
582
583 if (!rootOp)
584 return emitOpError("yielded value has no defining op");
585
586 if (rootOp->getParentOp() != getOperation())
587 return emitOpError("yielded value not defined within expression");
588
589 Type yieldType = yieldResult.getType();
590
591 if (resultType != yieldType)
592 return emitOpError("requires yielded type to match return type");
593
594 for (Operation &op : region.front().without_terminator()) {
595 auto expressionInterface = dyn_cast<emitc::CExpressionInterface>(op);
596 if (!expressionInterface)
597 return emitOpError("contains an unsupported operation");
598 if (op.getNumResults() != 1)
599 return emitOpError("requires exactly one result for each operation");
600 Value result = op.getResult(0);
601 if (result.use_empty())
602 return emitOpError("contains an unused operation");
603 }
604
605 // Make sure any operation with side effect is only reachable once from
606 // the root op, otherwise emission will be replicating side effects.
609 worklist.push_back(rootOp);
610 while (!worklist.empty()) {
611 Operation *op = worklist.back();
612 worklist.pop_back();
613 if (visited.contains(op)) {
614 auto cExpr = cast<CExpressionInterface>(op);
615 if (!cExpr.alwaysInline() && cExpr.hasSideEffects())
616 return emitOpError(
617 "requires exactly one use for operations with side effects");
618 }
619 visited.insert(op);
620 for (Value operand : op->getOperands())
621 if (Operation *def = operand.getDefiningOp()) {
622 worklist.push_back(def);
623 }
624 }
625
626 // It is illegal to forbid inlining of expressions whose root operation must
627 // be inlined.
628 if (getDoNotInline() &&
629 cast<emitc::CExpressionInterface>(rootOp).alwaysInline()) {
630 return emitOpError("root operation must be inlined but expression is marked"
631 " do-not-inline");
632 }
633
634 return success();
635}
636
637//===----------------------------------------------------------------------===//
638// ForOp
639//===----------------------------------------------------------------------===//
640
641void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
642 Value ub, Value step, BodyBuilderFn bodyBuilder) {
643 OpBuilder::InsertionGuard g(builder);
644 result.addOperands({lb, ub, step});
645 Type t = lb.getType();
646 Region *bodyRegion = result.addRegion();
647 Block *bodyBlock = builder.createBlock(bodyRegion);
648 bodyBlock->addArgument(t, result.location);
649
650 // Create the default terminator if the builder is not provided.
651 if (!bodyBuilder) {
652 ForOp::ensureTerminator(*bodyRegion, builder, result.location);
653 } else {
654 OpBuilder::InsertionGuard guard(builder);
655 builder.setInsertionPointToStart(bodyBlock);
656 bodyBuilder(builder, result.location, bodyBlock->getArgument(0));
657 }
658}
659
660void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}
661
662ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
663 Builder &builder = parser.getBuilder();
664 Type type;
665
666 OpAsmParser::Argument inductionVariable;
668
669 // Parse the induction variable followed by '='.
670 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
671 // Parse loop bounds.
672 parser.parseOperand(lb) || parser.parseKeyword("to") ||
673 parser.parseOperand(ub) || parser.parseKeyword("step") ||
674 parser.parseOperand(step))
675 return failure();
676
677 // Parse the optional initial iteration arguments.
679 regionArgs.push_back(inductionVariable);
680
681 // Parse optional type, else assume Index.
682 if (parser.parseOptionalColon())
683 type = builder.getIndexType();
684 else if (parser.parseType(type))
685 return failure();
686
687 // Resolve input operands.
688 regionArgs.front().type = type;
689 if (parser.resolveOperand(lb, type, result.operands) ||
690 parser.resolveOperand(ub, type, result.operands) ||
691 parser.resolveOperand(step, type, result.operands))
692 return failure();
693
694 // Parse the body region.
695 Region *body = result.addRegion();
696 if (parser.parseRegion(*body, regionArgs))
697 return failure();
698
699 ForOp::ensureTerminator(*body, builder, result.location);
700
701 // Parse the optional attribute list.
702 if (parser.parseOptionalAttrDict(result.attributes))
703 return failure();
704
705 return success();
706}
707
708void ForOp::print(OpAsmPrinter &p) {
709 p << " " << getInductionVar() << " = " << getLowerBound() << " to "
710 << getUpperBound() << " step " << getStep();
711
712 p << ' ';
713 if (Type t = getInductionVar().getType(); !t.isIndex())
714 p << " : " << t << ' ';
715 p.printRegion(getRegion(),
716 /*printEntryBlockArgs=*/false,
717 /*printBlockTerminators=*/false);
718 p.printOptionalAttrDict((*this)->getDiscardableAttrDictionary().getValue());
719}
720
721LogicalResult ForOp::verifyRegions() {
722 // Check that the body defines as single block argument for the induction
723 // variable.
724 if (getBody()->getNumArguments() != 1)
725 return emitOpError("expected body to have a single block argument for the "
726 "induction variable");
727
728 if (getInductionVar().getType() != getLowerBound().getType())
729 return emitOpError(
730 "expected induction variable to be same type as bounds and step");
731
732 return success();
733}
734
735//===----------------------------------------------------------------------===//
736// CallOp
737//===----------------------------------------------------------------------===//
738
739LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
740 // Check that the callee attribute was specified.
741 auto fnAttr = getCalleeAttr();
742 if (!fnAttr)
743 return emitOpError("requires a 'callee' symbol reference attribute");
744 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
745 if (!fn)
746 return emitOpError() << "'" << fnAttr.getValue()
747 << "' does not reference a valid function";
748
749 // Verify that the operand and result types match the callee.
751}
752
753FunctionType CallOp::getCalleeType() {
754 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
755}
756
757//===----------------------------------------------------------------------===//
758// DeclareFuncOp
759//===----------------------------------------------------------------------===//
760
761LogicalResult
762DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
763 // Check that the sym_name attribute was specified.
764 auto fnAttr = getSymNameAttr();
765 if (!fnAttr)
766 return emitOpError("requires a 'sym_name' symbol reference attribute");
767 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
768 if (!fn)
769 return emitOpError() << "'" << fnAttr.getValue()
770 << "' does not reference a valid function";
771
772 return success();
773}
774
775//===----------------------------------------------------------------------===//
776// FuncOp
777//===----------------------------------------------------------------------===//
778
779void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
780 FunctionType type, ArrayRef<NamedAttribute> attrs,
781 ArrayRef<DictionaryAttr> argAttrs) {
782 state.addAttribute(getSymNameAttrName(state.name),
783 builder.getStringAttr(name));
784 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
785 state.attributes.append(attrs.begin(), attrs.end());
786 state.addRegion();
787
788 if (argAttrs.empty())
789 return;
790 assert(type.getNumInputs() == argAttrs.size());
792 builder, state, argAttrs, /*resultAttrs=*/{},
793 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
794}
795
796ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
797 auto buildFuncType =
798 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
800 std::string &) { return builder.getFunctionType(argTypes, results); };
801
803 parser, result, /*allowVariadic=*/false,
804 getFunctionTypeAttrName(result.name), buildFuncType,
805 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
806}
807
808void FuncOp::print(OpAsmPrinter &p) {
810 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
811 getArgAttrsAttrName(), getResAttrsAttrName());
812}
813
814LogicalResult FuncOp::verify() {
815 if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {
816 return emitOpError("cannot have lvalue type as argument");
817 }
818
819 if (getNumResults() > 1)
820 return emitOpError("requires zero or exactly one result, but has ")
821 << getNumResults();
822
823 if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
824 return emitOpError("cannot return array type");
825
826 return success();
827}
828
829//===----------------------------------------------------------------------===//
830// ReturnOp
831//===----------------------------------------------------------------------===//
832
833LogicalResult ReturnOp::verify() {
834 auto function = cast<FuncOp>((*this)->getParentOp());
835
836 // The operand number and types must match the function signature.
837 if (getNumOperands() != function.getNumResults())
838 return emitOpError("has ")
839 << getNumOperands() << " operands, but enclosing function (@"
840 << function.getName() << ") returns " << function.getNumResults();
841
842 if (function.getNumResults() == 1)
843 if (getOperand().getType() != function.getResultTypes()[0])
844 return emitError() << "type of the return operand ("
845 << getOperand().getType()
846 << ") doesn't match function result type ("
847 << function.getResultTypes()[0] << ")"
848 << " in function @" << function.getName();
849 return success();
850}
851
852//===----------------------------------------------------------------------===//
853// IfOp
854//===----------------------------------------------------------------------===//
855
856void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
857 bool addThenBlock, bool addElseBlock) {
858 assert((!addElseBlock || addThenBlock) &&
859 "must not create else block w/o then block");
860 result.addOperands(cond);
861
862 // Add regions and blocks.
863 OpBuilder::InsertionGuard guard(builder);
864 Region *thenRegion = result.addRegion();
865 if (addThenBlock)
866 builder.createBlock(thenRegion);
867 Region *elseRegion = result.addRegion();
868 if (addElseBlock)
869 builder.createBlock(elseRegion);
870}
871
872void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
873 bool withElseRegion) {
874 result.addOperands(cond);
875
876 // Build then region.
877 OpBuilder::InsertionGuard guard(builder);
878 Region *thenRegion = result.addRegion();
879 builder.createBlock(thenRegion);
880
881 // Build else region.
882 Region *elseRegion = result.addRegion();
883 if (withElseRegion) {
884 builder.createBlock(elseRegion);
885 }
886}
887
888void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
889 function_ref<void(OpBuilder &, Location)> thenBuilder,
890 function_ref<void(OpBuilder &, Location)> elseBuilder) {
891 assert(thenBuilder && "the builder callback for 'then' must be present");
892 result.addOperands(cond);
893
894 // Build then region.
895 OpBuilder::InsertionGuard guard(builder);
896 Region *thenRegion = result.addRegion();
897 builder.createBlock(thenRegion);
898 thenBuilder(builder, result.location);
899
900 // Build else region.
901 Region *elseRegion = result.addRegion();
902 if (elseBuilder) {
903 builder.createBlock(elseRegion);
904 elseBuilder(builder, result.location);
905 }
906}
907
908ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) {
909 // Create the regions for 'then'.
910 result.regions.reserve(2);
911 Region *thenRegion = result.addRegion();
912 Region *elseRegion = result.addRegion();
913
914 Builder &builder = parser.getBuilder();
916 Type i1Type = builder.getIntegerType(1);
917 if (parser.parseOperand(cond) ||
918 parser.resolveOperand(cond, i1Type, result.operands))
919 return failure();
920 // Parse the 'then' region.
921 if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))
922 return failure();
923 IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
924
925 // If we find an 'else' keyword then parse the 'else' region.
926 if (!parser.parseOptionalKeyword("else")) {
927 if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))
928 return failure();
929 IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
930 }
931
932 // Parse the optional attribute list.
933 if (parser.parseOptionalAttrDict(result.attributes))
934 return failure();
935 return success();
936}
937
938void IfOp::print(OpAsmPrinter &p) {
939 bool printBlockTerminators = false;
940
941 p << " " << getCondition();
942 p << ' ';
943 p.printRegion(getThenRegion(),
944 /*printEntryBlockArgs=*/false,
945 /*printBlockTerminators=*/printBlockTerminators);
946
947 // Print the 'else' regions if it exists and has a block.
948 Region &elseRegion = getElseRegion();
949 if (!elseRegion.empty()) {
950 p << " else ";
951 p.printRegion(elseRegion,
952 /*printEntryBlockArgs=*/false,
953 /*printBlockTerminators=*/printBlockTerminators);
954 }
955
956 p.printOptionalAttrDict((*this)->getDiscardableAttrDictionary().getValue());
957}
958
959/// Given the region at `index`, or the parent operation if `index` is None,
960/// return the successor regions. These are the regions that may be selected
961/// during the flow of control. `operands` is a set of optional attributes
962/// that correspond to a constant value for each operand, or null if that
963/// operand is not a constant.
964void IfOp::getSuccessorRegions(RegionBranchPoint point,
966 // The `then` and the `else` region branch back to the parent operation.
967 if (!point.isParent()) {
968 regions.push_back(RegionSuccessor(getOperation()));
969 return;
970 }
971
972 regions.push_back(RegionSuccessor(&getThenRegion()));
973
974 // Don't consider the else region if it is empty.
975 Region *elseRegion = &this->getElseRegion();
976 if (elseRegion->empty())
977 regions.push_back(RegionSuccessor(getOperation()));
978 else
979 regions.push_back(RegionSuccessor(elseRegion));
980}
981
982ValueRange IfOp::getSuccessorInputs(RegionSuccessor successor) {
983 return successor.isOperation() ? ValueRange(getOperation()->getResults())
984 : ValueRange();
985}
986
987void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,
989 FoldAdaptor adaptor(operands, *this);
990 auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
991 if (!boolAttr || boolAttr.getValue())
992 regions.emplace_back(&getThenRegion());
993
994 // If the else region is empty, execution continues after the parent op.
995 if (!boolAttr || !boolAttr.getValue()) {
996 if (!getElseRegion().empty())
997 regions.emplace_back(&getElseRegion());
998 else
999 regions.emplace_back(RegionSuccessor(getOperation()));
1000 }
1001}
1002
1003void IfOp::getRegionInvocationBounds(
1004 ArrayRef<Attribute> operands,
1005 SmallVectorImpl<InvocationBounds> &invocationBounds) {
1006 if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
1007 // If the condition is known, then one region is known to be executed once
1008 // and the other zero times.
1009 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
1010 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
1011 } else {
1012 // Non-constant condition. Each region may be executed 0 or 1 times.
1013 invocationBounds.assign(2, {0, 1});
1014 }
1015}
1016
1017//===----------------------------------------------------------------------===//
1018// IncludeOp
1019//===----------------------------------------------------------------------===//
1020
1021void IncludeOp::print(OpAsmPrinter &p) {
1022 bool standardInclude = getIsStandardInclude();
1023
1024 p << " ";
1025 if (standardInclude)
1026 p << "<";
1027 p << "\"" << getInclude() << "\"";
1028 if (standardInclude)
1029 p << ">";
1030}
1031
1032ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {
1033 bool standardInclude = !parser.parseOptionalLess();
1034
1035 StringAttr include;
1036 OptionalParseResult includeParseResult =
1037 parser.parseOptionalAttribute(include, "include", result.attributes);
1038 if (!includeParseResult.has_value())
1039 return parser.emitError(parser.getNameLoc()) << "expected string attribute";
1040
1041 if (standardInclude && parser.parseOptionalGreater())
1042 return parser.emitError(parser.getNameLoc())
1043 << "expected trailing '>' for standard include";
1044
1045 if (standardInclude)
1046 result.addAttribute("is_standard_include",
1047 UnitAttr::get(parser.getContext()));
1048
1049 return success();
1050}
1051
1052//===----------------------------------------------------------------------===//
1053// LiteralOp
1054//===----------------------------------------------------------------------===//
1055
1056/// The literal op requires a non-empty value.
1057LogicalResult emitc::LiteralOp::verify() {
1058 if (getValue().empty())
1059 return emitOpError() << "value must not be empty";
1060 return success();
1061}
1062
1063//===----------------------------------------------------------------------===//
1064// MemberOp
1065//===----------------------------------------------------------------------===//
1066
1067LogicalResult MemberOp::verify() {
1068 Type operandType = getOperand().getType();
1069 Type resultType = getResult().getType();
1070 bool resultIsWritable = isa<emitc::LValueType, emitc::ArrayType>(resultType);
1071
1072 // Make sure the operand and return type agree on value/memory semantics:
1073 // If the operand is an lvalue it models a memory location and as such its
1074 // elements are also memory locations: They require a load operation to use
1075 // their value and they can be assigned new values.
1076 // If the operand isn't an lvalue it models an aggregate SSA value and as
1077 // such its elements are also SSA values: Their value can be used directly
1078 // but they cannot be assigned to.
1079
1080 if (isa<emitc::LValueType>(operandType) && !resultIsWritable)
1081 return emitOpError("lvalues must return lvalues or arrays");
1082
1083 if (!isa<emitc::LValueType>(operandType) && resultIsWritable)
1084 return emitOpError("non-lvalues cannot return lvalues or arrays");
1085
1086 return success();
1087}
1088
1089//===----------------------------------------------------------------------===//
1090// SubOp
1091//===----------------------------------------------------------------------===//
1092
1093LogicalResult SubOp::verify() {
1094 Type lhsType = getLhs().getType();
1095 Type rhsType = getRhs().getType();
1096 Type resultType = getResult().getType();
1097
1098 if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
1099 return emitOpError("rhs can only be a pointer if lhs is a pointer");
1100
1101 if (isa<emitc::PointerType>(lhsType) &&
1102 !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
1103 return emitOpError("requires that rhs is an integer, pointer or of opaque "
1104 "type if lhs is a pointer");
1105
1106 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
1107 !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))
1108 return emitOpError("requires that the result is an integer, ptrdiff_t or "
1109 "of opaque type if lhs and rhs are pointers");
1110 return success();
1111}
1112
1113//===----------------------------------------------------------------------===//
1114// VariableOp
1115//===----------------------------------------------------------------------===//
1116
1117LogicalResult emitc::VariableOp::verify() {
1118 return verifyInitializationAttribute(getOperation(), getValueAttr());
1119}
1120
1121//===----------------------------------------------------------------------===//
1122// YieldOp
1123//===----------------------------------------------------------------------===//
1124
1125LogicalResult emitc::YieldOp::verify() {
1126 Value result = getResult();
1127 Operation *containingOp = getOperation()->getParentOp();
1128
1129 if (!isa<DoOp>(containingOp) && result && containingOp->getNumResults() != 1)
1130 return emitOpError() << "yields a value not returned by parent";
1131
1132 if (!isa<DoOp>(containingOp) && !result && containingOp->getNumResults() != 0)
1133 return emitOpError() << "does not yield a value to be returned by parent";
1134
1135 if (result && isa<emitc::LValueType>(result.getType()) &&
1136 !isa<ExpressionOp>(containingOp))
1137 return emitOpError() << "yielding lvalues is not supported for this op";
1138
1139 return success();
1140}
1141
1142//===----------------------------------------------------------------------===//
1143// SubscriptOp
1144//===----------------------------------------------------------------------===//
1145
1146LogicalResult emitc::SubscriptOp::verify() {
1147 // Checks for array operand.
1148 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {
1149 // Check number of indices.
1150 if (getIndices().size() != (size_t)arrayType.getRank()) {
1151 return emitOpError() << "on array operand requires number of indices ("
1152 << getIndices().size()
1153 << ") to match the rank of the array type ("
1154 << arrayType.getRank() << ")";
1155 }
1156 // Check types of index operands.
1157 for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {
1158 Type type = getIndices()[i].getType();
1159 if (!isIntegerIndexOrOpaqueType(type)) {
1160 return emitOpError() << "on array operand requires index operand " << i
1161 << " to be integer-like, but got " << type;
1162 }
1163 }
1164 // Check element type.
1165 Type elementType = arrayType.getElementType();
1166 Type resultType = getType().getValueType();
1167 if (elementType != resultType) {
1168 return emitOpError() << "on array operand requires element type ("
1169 << elementType << ") and result type (" << resultType
1170 << ") to match";
1171 }
1172 return success();
1173 }
1174
1175 // Checks for pointer operand.
1176 if (auto pointerType =
1177 llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {
1178 // Check number of indices.
1179 if (getIndices().size() != 1) {
1180 return emitOpError()
1181 << "on pointer operand requires one index operand, but got "
1182 << getIndices().size();
1183 }
1184 // Check types of index operand.
1185 Type type = getIndices()[0].getType();
1186 if (!isIntegerIndexOrOpaqueType(type)) {
1187 return emitOpError() << "on pointer operand requires index operand to be "
1188 "integer-like, but got "
1189 << type;
1190 }
1191 // Check pointee type.
1192 Type pointeeType = pointerType.getPointee();
1193 Type resultType = getType().getValueType();
1194 if (pointeeType != resultType) {
1195 return emitOpError() << "on pointer operand requires pointee type ("
1196 << pointeeType << ") and result type (" << resultType
1197 << ") to match";
1198 }
1199 return success();
1200 }
1201
1202 // The operand has opaque type, so we can't assume anything about the number
1203 // or types of index operands.
1204 return success();
1205}
1206
1207//===----------------------------------------------------------------------===//
1208// VerbatimOp
1209//===----------------------------------------------------------------------===//
1210
1211LogicalResult emitc::VerbatimOp::verify() {
1212 auto errorCallback = [&]() -> InFlightDiagnostic {
1213 return this->emitOpError();
1214 };
1215 FailureOr<SmallVector<ReplacementItem>> fmt =
1216 ::parseFormatString(getValue(), getFmtArgs(), errorCallback);
1217 if (failed(fmt))
1218 return failure();
1219
1220 size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) {
1221 return std::holds_alternative<Placeholder>(item);
1222 });
1223
1224 if (numPlaceholders != getFmtArgs().size()) {
1225 return emitOpError()
1226 << "requires operands for each placeholder in the format string";
1227 }
1228 return success();
1229}
1230
1231FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {
1232 // Error checking is done in verify.
1233 return ::parseFormatString(getValue(), getFmtArgs());
1234}
1235
1236//===----------------------------------------------------------------------===//
1237// EmitC Enums
1238//===----------------------------------------------------------------------===//
1239
1240#include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
1241
1242//===----------------------------------------------------------------------===//
1243// EmitC Attributes
1244//===----------------------------------------------------------------------===//
1245
1246#define GET_ATTRDEF_CLASSES
1247#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
1248
1249//===----------------------------------------------------------------------===//
1250// EmitC Types
1251//===----------------------------------------------------------------------===//
1252
1253#define GET_TYPEDEF_CLASSES
1254#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
1255
1256//===----------------------------------------------------------------------===//
1257// ArrayType
1258//===----------------------------------------------------------------------===//
1259
1260Type emitc::ArrayType::parse(AsmParser &parser) {
1261 if (parser.parseLess())
1262 return Type();
1263
1264 SmallVector<int64_t, 4> dimensions;
1265 if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,
1266 /*withTrailingX=*/true))
1267 return Type();
1268 // Parse the element type.
1269 auto typeLoc = parser.getCurrentLocation();
1270 Type elementType;
1271 if (parser.parseType(elementType))
1272 return Type();
1273
1274 // Check that array is formed from allowed types.
1275 if (!isValidElementType(elementType))
1276 return parser.emitError(typeLoc, "invalid array element type '")
1277 << elementType << "'",
1278 Type();
1279 if (parser.parseGreater())
1280 return Type();
1281 return parser.getChecked<ArrayType>(dimensions, elementType);
1282}
1283
1284void emitc::ArrayType::print(AsmPrinter &printer) const {
1285 printer << "<";
1286 for (int64_t dim : getShape()) {
1287 printer << dim << 'x';
1288 }
1289 printer.printType(getElementType());
1290 printer << ">";
1291}
1292
1293LogicalResult emitc::ArrayType::verify(
1295 ::llvm::ArrayRef<int64_t> shape, Type elementType) {
1296 if (shape.empty())
1297 return emitError() << "shape must not be empty";
1298
1299 for (int64_t dim : shape) {
1300 if (dim < 0)
1301 return emitError() << "dimensions must have non-negative size";
1302 }
1303
1304 if (!elementType)
1305 return emitError() << "element type must not be none";
1306
1307 if (!isValidElementType(elementType))
1308 return emitError() << "invalid array element type";
1309
1310 return success();
1311}
1312
1313emitc::ArrayType
1314emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
1315 Type elementType) const {
1316 if (!shape)
1317 return emitc::ArrayType::get(getShape(), elementType);
1318 return emitc::ArrayType::get(*shape, elementType);
1319}
1320
1321//===----------------------------------------------------------------------===//
1322// LValueType
1323//===----------------------------------------------------------------------===//
1324
1325LogicalResult mlir::emitc::LValueType::verify(
1327 mlir::Type value) {
1328 // Check that the wrapped type is valid. This especially forbids nested
1329 // lvalue types.
1330 if (!isSupportedEmitCType(value))
1331 return emitError()
1332 << "!emitc.lvalue must wrap supported emitc type, but got " << value;
1333
1334 if (llvm::isa<emitc::ArrayType>(value))
1335 return emitError() << "!emitc.lvalue cannot wrap !emitc.array type";
1336
1337 return success();
1338}
1339
1340//===----------------------------------------------------------------------===//
1341// OpaqueType
1342//===----------------------------------------------------------------------===//
1343
1344LogicalResult mlir::emitc::OpaqueType::verify(
1346 llvm::StringRef value) {
1347 if (value.empty()) {
1348 return emitError() << "expected non empty string in !emitc.opaque type";
1349 }
1350 if (value.back() == '*') {
1351 return emitError() << "pointer not allowed as outer type with "
1352 "!emitc.opaque, use !emitc.ptr instead";
1353 }
1354 return success();
1355}
1356
1357//===----------------------------------------------------------------------===//
1358// PointerType
1359//===----------------------------------------------------------------------===//
1360
1361LogicalResult mlir::emitc::PointerType::verify(
1363 if (llvm::isa<emitc::LValueType>(value))
1364 return emitError() << "pointers to lvalues are not allowed";
1365
1366 return success();
1367}
1368
1369//===----------------------------------------------------------------------===//
1370// GlobalOp
1371//===----------------------------------------------------------------------===//
1373 TypeAttr type,
1374 Attribute initialValue) {
1375 p << type;
1376 if (initialValue) {
1377 p << " = ";
1378 p.printAttributeWithoutType(initialValue);
1379 }
1380}
1381
1383 if (auto array = llvm::dyn_cast<ArrayType>(type))
1384 return RankedTensorType::get(array.getShape(), array.getElementType());
1385 return type;
1386}
1387
1388static ParseResult
1390 Attribute &initialValue) {
1391 Type type;
1392 if (parser.parseType(type))
1393 return failure();
1394
1395 typeAttr = TypeAttr::get(type);
1396
1397 if (parser.parseOptionalEqual())
1398 return success();
1399
1400 if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))
1401 return failure();
1402
1403 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1404 initialValue))
1405 return parser.emitError(parser.getNameLoc())
1406 << "initial value should be a integer, float, elements or opaque "
1407 "attribute";
1408 return success();
1409}
1410
1411LogicalResult GlobalOp::verify() {
1412 if (!isSupportedEmitCType(getType())) {
1413 return emitOpError("expected valid emitc type");
1414 }
1415 if (getInitialValue().has_value()) {
1416 Attribute initValue = getInitialValue().value();
1417 // Check that the type of the initial value is compatible with the type of
1418 // the global variable.
1419 if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1420 auto arrayType = llvm::dyn_cast<ArrayType>(getType());
1421 if (!arrayType)
1422 return emitOpError("expected array type, but got ") << getType();
1423
1424 Type initType = elementsAttr.getType();
1426 if (initType != tensorType) {
1427 return emitOpError("initial value expected to be of type ")
1428 << getType() << ", but was of type " << initType;
1429 }
1430 } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1431 if (intAttr.getType() != getType()) {
1432 return emitOpError("initial value expected to be of type ")
1433 << getType() << ", but was of type " << intAttr.getType();
1434 }
1435 } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1436 if (floatAttr.getType() != getType()) {
1437 return emitOpError("initial value expected to be of type ")
1438 << getType() << ", but was of type " << floatAttr.getType();
1439 }
1440 } else if (!isa<emitc::OpaqueAttr>(initValue)) {
1441 return emitOpError("initial value should be a integer, float, elements "
1442 "or opaque attribute, but got ")
1443 << initValue;
1444 }
1445 }
1446 if (getStaticSpecifier() && getExternSpecifier()) {
1447 return emitOpError("cannot have both static and extern specifiers");
1448 }
1449 return success();
1450}
1451
1452//===----------------------------------------------------------------------===//
1453// GetGlobalOp
1454//===----------------------------------------------------------------------===//
1455
1456LogicalResult
1457GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1458 // Verify that the type matches the type of the global variable.
1459 auto global =
1460 symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1461 if (!global)
1462 return emitOpError("'")
1463 << getName() << "' does not reference a valid emitc.global";
1464
1465 Type resultType = getResult().getType();
1466 Type globalType = global.getType();
1467
1468 // global has array type
1469 if (llvm::isa<ArrayType>(globalType)) {
1470 if (globalType != resultType)
1471 return emitOpError("on array type expects result type ")
1472 << resultType << " to match type " << globalType
1473 << " of the global @" << getName();
1474 return success();
1475 }
1476
1477 // global has non-array type
1478 auto lvalueType = dyn_cast<LValueType>(resultType);
1479 if (!lvalueType)
1480 return emitOpError("on non-array type expects result type to be an "
1481 "lvalue type for the global @")
1482 << getName();
1483 if (lvalueType.getValueType() != globalType)
1484 return emitOpError("on non-array type expects result inner type ")
1485 << lvalueType.getValueType() << " to match type " << globalType
1486 << " of the global @" << getName();
1487 return success();
1488}
1489
1490//===----------------------------------------------------------------------===//
1491// SwitchOp
1492//===----------------------------------------------------------------------===//
1493
1494/// Parse the case regions and values.
1495static ParseResult
1497 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
1498 SmallVector<int64_t> caseValues;
1499 while (succeeded(parser.parseOptionalKeyword("case"))) {
1500 int64_t value;
1501 Region &region = *caseRegions.emplace_back(std::make_unique<Region>());
1502 if (parser.parseInteger(value) ||
1503 parser.parseRegion(region, /*arguments=*/{}))
1504 return failure();
1505 caseValues.push_back(value);
1506 }
1507 cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);
1508 return success();
1509}
1510
1511/// Print the case regions and values.
1513 DenseI64ArrayAttr cases, RegionRange caseRegions) {
1514 for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {
1515 p.printNewline();
1516 p << "case " << value << ' ';
1517 p.printRegion(*region, /*printEntryBlockArgs=*/false);
1518 }
1519}
1520
1521static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region,
1522 const Twine &name) {
1523 auto yield = dyn_cast<emitc::YieldOp>(region.front().back());
1524 if (!yield)
1525 return op.emitOpError("expected region to end with emitc.yield, but got ")
1526 << region.front().back().getName();
1527
1528 if (yield.getNumOperands() != 0) {
1529 return (op.emitOpError("expected each region to return ")
1530 << "0 values, but " << name << " returns "
1531 << yield.getNumOperands())
1532 .attachNote(yield.getLoc())
1533 << "see yield operation here";
1534 }
1535
1536 return success();
1537}
1538
1539LogicalResult emitc::SwitchOp::verify() {
1540 if (!isIntegerIndexOrOpaqueType(getArg().getType()))
1541 return emitOpError("unsupported type ") << getArg().getType();
1542
1543 if (getCases().size() != getCaseRegions().size()) {
1544 return emitOpError("has ")
1545 << getCaseRegions().size() << " case regions but "
1546 << getCases().size() << " case values";
1547 }
1548
1549 DenseSet<int64_t> valueSet;
1550 for (int64_t value : getCases())
1551 if (!valueSet.insert(value).second)
1552 return emitOpError("has duplicate case value: ") << value;
1553
1554 if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))
1555 return failure();
1556
1557 for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
1558 if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))
1559 return failure();
1560
1561 return success();
1562}
1563
1564unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }
1565
1566Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }
1567
1568Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {
1569 assert(idx < getNumCases() && "case index out-of-bounds");
1570 return getCaseRegions()[idx].front();
1571}
1572
1573void SwitchOp::getSuccessorRegions(
1575 llvm::append_range(successors, getRegions());
1576}
1577
1578/// Returns the int64_t value of an IntegerAttr regardless of whether its type
1579/// is signless, signed, or unsigned. Returns std::nullopt for unknown types.
1580static std::optional<int64_t> getIntAttrValue(IntegerAttr attr) {
1581 Type type = attr.getType();
1582 if (type.isIndex() || type.isSignlessInteger())
1583 return attr.getInt();
1584 if (type.isSignedInteger())
1585 return attr.getSInt();
1586 if (type.isUnsignedInteger())
1587 return static_cast<int64_t>(attr.getUInt());
1588 return std::nullopt;
1589}
1590
1591void SwitchOp::getEntrySuccessorRegions(
1592 ArrayRef<Attribute> operands,
1594 FoldAdaptor adaptor(operands, *this);
1595
1596 // If a constant was not provided, all regions are possible successors.
1597 auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
1598 if (!arg) {
1599 llvm::append_range(successors, getRegions());
1600 return;
1601 }
1602
1603 std::optional<int64_t> argValue = getIntAttrValue(arg);
1604 if (!argValue) {
1605 // Unknown type; conservatively treat all regions as possible.
1606 llvm::append_range(successors, getRegions());
1607 return;
1608 }
1609
1610 // Otherwise, try to find a case with a matching value. If not, the
1611 // default region is the only successor.
1612 for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
1613 if (caseValue == *argValue) {
1614 successors.emplace_back(&caseRegion);
1615 return;
1616 }
1617 }
1618 successors.emplace_back(&getDefaultRegion());
1619}
1620
1621void SwitchOp::getRegionInvocationBounds(
1623 auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
1624 if (!operandValue) {
1625 // All regions are invoked at most once.
1626 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1627 return;
1628 }
1629
1630 std::optional<int64_t> maybeIntValue = getIntAttrValue(operandValue);
1631 if (!maybeIntValue) {
1632 // Unknown type; conservatively treat all regions as possible.
1633 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1634 return;
1635 }
1636
1637 unsigned liveIndex = getNumRegions() - 1;
1638 const auto *iteratorToInt = llvm::find(getCases(), *maybeIntValue);
1639
1640 liveIndex = iteratorToInt != getCases().end()
1641 ? std::distance(getCases().begin(), iteratorToInt)
1642 : liveIndex;
1643
1644 for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
1645 ++regIndex)
1646 bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
1647}
1648
1649//===----------------------------------------------------------------------===//
1650// FileOp
1651//===----------------------------------------------------------------------===//
1652void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {
1653 state.addRegion()->emplaceBlock();
1654 state.attributes.push_back(
1655 builder.getNamedAttr("id", builder.getStringAttr(id)));
1656}
1657
1658//===----------------------------------------------------------------------===//
1659// FieldOp
1660//===----------------------------------------------------------------------===//
1661
1663 TypeAttr type,
1664 Attribute initialValue) {
1665 p << type;
1666 if (initialValue) {
1667 p << " = ";
1668 p.printAttributeWithoutType(initialValue);
1669 }
1670}
1671
1673 if (auto array = llvm::dyn_cast<ArrayType>(type))
1674 return RankedTensorType::get(array.getShape(), array.getElementType());
1675 return type;
1676}
1677
1678static ParseResult
1680 Attribute &initialValue) {
1681 Type type;
1682 if (parser.parseType(type))
1683 return failure();
1684
1685 typeAttr = TypeAttr::get(type);
1686
1687 if (parser.parseOptionalEqual())
1688 return success();
1689
1690 if (parser.parseAttribute(initialValue, getInitializerTypeForField(type)))
1691 return failure();
1692
1693 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1694 initialValue))
1695 return parser.emitError(parser.getNameLoc())
1696 << "initial value should be a integer, float, elements or opaque "
1697 "attribute";
1698 return success();
1699}
1700
1701LogicalResult FieldOp::verify() {
1703 return emitOpError("expected valid emitc type");
1704
1705 Operation *parentOp = getOperation()->getParentOp();
1706 if (!parentOp || !isa<emitc::ClassOp>(parentOp))
1707 return emitOpError("field must be nested within an emitc.class operation");
1708
1709 StringAttr symName = getSymNameAttr();
1710 if (!symName || symName.getValue().empty())
1711 return emitOpError("field must have a non-empty symbol name");
1712
1713 return success();
1714}
1715
1716//===----------------------------------------------------------------------===//
1717// GetFieldOp
1718//===----------------------------------------------------------------------===//
1719
1720LogicalResult GetFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1721 mlir::FlatSymbolRefAttr fieldNameAttr = getFieldNameAttr();
1722 FieldOp fieldOp =
1723 symbolTable.lookupNearestSymbolFrom<FieldOp>(*this, fieldNameAttr);
1724 if (!fieldOp)
1725 return emitOpError("field '")
1726 << fieldNameAttr << "' not found in the class";
1727
1728 Type getFieldResultType = getResult().getType();
1729 Type fieldType = fieldOp.getType();
1730
1731 if (fieldType != getFieldResultType)
1732 return emitOpError("result type ")
1733 << getFieldResultType << " does not match field '" << fieldNameAttr
1734 << "' type " << fieldType;
1735
1736 return success();
1737}
1738
1739//===----------------------------------------------------------------------===//
1740// DoOp
1741//===----------------------------------------------------------------------===//
1742
1743void DoOp::print(OpAsmPrinter &p) {
1744 p << ' ';
1745 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
1746 p << " while ";
1747 p.printRegion(getConditionRegion());
1749 getOperation()->getDiscardableAttrDictionary().getValue());
1750}
1751
1752LogicalResult emitc::DoOp::verify() {
1753 Block &condBlock = getConditionRegion().front();
1754
1755 if (condBlock.getOperations().size() != 2)
1756 return emitOpError(
1757 "condition region must contain exactly two operations: "
1758 "'emitc.expression' followed by 'emitc.yield', but found ")
1759 << condBlock.getOperations().size() << " operations";
1760
1761 Operation &first = condBlock.front();
1762 auto exprOp = dyn_cast<emitc::ExpressionOp>(first);
1763 if (!exprOp)
1764 return emitOpError("expected first op in condition region to be "
1765 "'emitc.expression', but got ")
1766 << first.getName();
1767
1768 if (!exprOp.getResult().getType().isInteger(1))
1769 return emitOpError("emitc.expression in condition region must return "
1770 "'i1', but returns ")
1771 << exprOp.getResult().getType();
1772
1773 Operation &last = condBlock.back();
1774 auto condYield = dyn_cast<emitc::YieldOp>(last);
1775 if (!condYield)
1776 return emitOpError("expected last op in condition region to be "
1777 "'emitc.yield', but got ")
1778 << last.getName();
1779
1780 if (condYield.getNumOperands() != 1)
1781 return emitOpError("expected condition region to return 1 value, but "
1782 "it returns ")
1783 << condYield.getNumOperands() << " values";
1784
1785 if (condYield.getOperand(0) != exprOp.getResult())
1786 return emitError("'emitc.yield' must return result of "
1787 "'emitc.expression' from this condition region");
1788
1789 Block &bodyBlock = getBodyRegion().front();
1790 if (bodyBlock.mightHaveTerminator())
1791 return emitOpError("body region must not contain terminator");
1792
1793 return success();
1794}
1795
1796ParseResult DoOp::parse(OpAsmParser &parser, OperationState &result) {
1797 Region *bodyRegion = result.addRegion();
1798 Region *condRegion = result.addRegion();
1799
1800 if (parser.parseRegion(*bodyRegion) || parser.parseKeyword("while") ||
1801 parser.parseRegion(*condRegion))
1802 return failure();
1803
1804 if (bodyRegion->empty())
1805 bodyRegion->emplaceBlock();
1806
1807 return parser.parseOptionalAttrDictWithKeyword(result.attributes);
1808}
1809
1810//===----------------------------------------------------------------------===//
1811// TableGen'd op method definitions
1812//===----------------------------------------------------------------------===//
1813
1814#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"
1815
1816#define GET_OP_CLASSES
1817#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
static Value getPointer(Location loc, Value value, ConversionPatternRewriter &rewriter)
return success()
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static std::optional< int64_t > getLowerBound(Value iv)
Gets the constant lower bound on an iv.
static std::optional< int64_t > getIntAttrValue(IntegerAttr attr)
Returns the int64_t value of an IntegerAttr regardless of whether its type is signless,...
Definition EmitC.cpp:1580
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:143
static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region, const Twine &name)
Definition EmitC.cpp:1521
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1389
static Type getInitializerTypeForField(Type type)
Definition EmitC.cpp:1672
static ParseResult parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1679
FailureOr< SmallVector< ReplacementItem > > parseFormatString(StringRef toParse, ArgType fmtArgs, llvm::function_ref< mlir::InFlightDiagnostic()> emitError={})
Parse a format string and return a list of its parts.
Definition EmitC.cpp:178
static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, TypeAttr type, Attribute initialValue)
Definition EmitC.cpp:1372
static LogicalResult verifyAssignmentOp(AssignmentOp op)
Definition EmitC.cpp:268
static ParseResult parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, SmallVectorImpl< std::unique_ptr< Region > > &caseRegions)
Parse the case regions and values.
Definition EmitC.cpp:1496
static LogicalResult verifyOpaqueCallCommon(Operation *op, StringRef callee, std::optional< ArrayAttr > args, std::optional< ArrayAttr > templateArgs, TypeRange resultTypes, size_t numArgsOperands)
Definition EmitC.cpp:336
static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op, TypeAttr type, Attribute initialValue)
Definition EmitC.cpp:1662
static void printSwitchCases(OpAsmPrinter &p, Operation *op, DenseI64ArrayAttr cases, RegionRange caseRegions)
Print the case regions and values.
Definition EmitC.cpp:1512
static Type getInitializerTypeForGlobal(Type type)
Definition EmitC.cpp:1382
b getContext())
static Type getValueType(Attribute attr)
Definition SPIRVOps.cpp:845
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:229
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Definition Traits.cpp:117
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalColon()=0
Parse a : token if present.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual ParseResult parseOptionalGreater()=0
Parse a '>' token if present.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual OptionalParseResult parseOptionalAttribute(Attribute &result, Type type={})=0
Parse an arbitrary optional attribute of a given type and return it in result.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
auto getChecked(SMLoc loc, ParamsT &&...params)
Invoke the getChecked method of the given Attribute or Type class, using the provided location to emi...
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalLess()=0
Parse a '<' token if present.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual void printType(Type type)
virtual void printNewline()
Print a newline and indent the printer to the start of the current operation/attribute/type.
Attributes are known-constant values of operations.
Definition Attributes.h:25
Block represents an ordered list of Operations.
Definition Block.h:34
BlockArgument getArgument(unsigned i)
Definition Block.h:154
OpListType & getOperations()
Definition Block.h:162
Operation & front()
Definition Block.h:178
Operation & back()
Definition Block.h:177
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition Block.cpp:158
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
Definition Block.cpp:255
BlockArgListType getArguments()
Definition Block.h:112
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
Definition Block.h:222
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
UnitAttr getUnitAttr()
Definition Builders.cpp:106
DenseI64ArrayAttr getDenseI64ArrayAttr(ArrayRef< int64_t > values)
Definition Builders.cpp:175
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition Builders.cpp:84
IntegerType getIntegerType(unsigned width)
Definition Builders.cpp:75
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:271
IndexType getIndexType()
Definition Builders.cpp:59
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition Builders.cpp:102
A symbol reference with a reference path containing a single element.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition IRMapping.h:30
This class represents a diagnostic that is inflight and set to be reported.
This class represents upper and lower bounds on the number of times a region of a RegionBranchOpInter...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void shadowRegionArgs(Region &region, ValueRange namesToUse)=0
Renumber the arguments for the specified region to the same names as the SSA values in namesToUse.
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with 'attribute...
void printOperands(OperandRange operands)
Print a comma separated range of operation operands out of line to avoid instantiating the range iter...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
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
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition Builders.cpp:439
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Definition Builders.cpp:581
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Definition Builders.h:415
This class represents a single result from folding an operation.
type_range getType() const
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:434
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:405
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
Definition Operation.h:431
This class implements Optional functionality for ParseResult.
bool has_value() const
Returns true if we contain a valid ParseResult value.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
This class provides an abstraction over the different types of ranges over Regions.
Definition Region.h:363
This class represents a successor of a region.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
Block & emplaceBlock()
Definition Region.h:46
bool empty()
Definition Region.h:60
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
This class represents a collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
Definition Types.cpp:78
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition Types.cpp:66
bool isIndex() const
Definition Types.cpp:56
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
Definition Types.cpp:90
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:392
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
A named class for passing around the variadic flag.
Speculatability
This enum is returned from the getSpeculatability method in the ConditionallySpeculatable op interfac...
constexpr auto Speculatable
constexpr auto NotSpeculatable
LogicalResult verifyCallOpInterface(CallOpInterface call, TypeRange argumentTypes, TypeRange resultTypes)
Verify that the forwarded operands and results of call are in a 1:1 relationship with the given argum...
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 buildTerminatedBody(OpBuilder &builder, Location loc)
Default callback for builders of ops carrying a region.
Definition EmitC.cpp:56
std::variant< StringRef, Placeholder > ReplacementItem
Definition EmitC.h:48
bool isFundamentalType(mlir::Type type)
Determines whether type is a valid fundamental C++ type in EmitC.
Definition EmitC.cpp:135
bool isSupportedFloatType(mlir::Type type)
Determines whether type is a valid floating-point type in EmitC.
Definition EmitC.cpp:115
bool isSupportedEmitCType(mlir::Type type)
Determines whether type is valid in EmitC.
Definition EmitC.cpp:60
bool isPointerWideType(mlir::Type type)
Determines whether type is a emitc.size_t/ssize_t type.
Definition EmitC.cpp:130
bool isIntegerIndexOrOpaqueType(Type type)
Determines whether type is integer like, i.e.
Definition EmitC.cpp:110
bool isSupportedIntegerType(mlir::Type type)
Determines whether type is a valid integer type in EmitC.
Definition EmitC.cpp:94
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
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
Include the generated interface declarations.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:311
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:125
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::SetVector< T, Vector, Set, N > SetVector
Definition LLVM.h:128
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
Definition Value.h:496
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:123
llvm::function_ref< Fn > function_ref
Definition LLVM.h:155
This is the representation of an operand reference.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
Region * addRegion()
Create a region that should be attached to the operation.