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