MLIR 23.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// ApplyOp
267//===----------------------------------------------------------------------===//
268
269LogicalResult ApplyOp::verify() {
270 StringRef applicableOperatorStr = getApplicableOperator();
271
272 // Applicable operator must not be empty.
273 if (applicableOperatorStr.empty())
274 return emitOpError("applicable operator must not be empty");
275
276 // Only `*` and `&` are supported.
277 if (applicableOperatorStr != "&" && applicableOperatorStr != "*")
278 return emitOpError("applicable operator is illegal");
279
280 Type operandType = getOperand().getType();
281 Type resultType = getResult().getType();
282 if (applicableOperatorStr == "&") {
283 if (!llvm::isa<emitc::LValueType>(operandType))
284 return emitOpError("operand type must be an lvalue when applying `&`");
285 if (!llvm::isa<emitc::PointerType>(resultType))
286 return emitOpError("result type must be a pointer when applying `&`");
287 } else {
288 if (!llvm::isa<emitc::PointerType>(operandType))
289 return emitOpError("operand type must be a pointer when applying `*`");
290 }
291
292 return success();
293}
294
295//===----------------------------------------------------------------------===//
296// AssignOp
297//===----------------------------------------------------------------------===//
298
299/// The assign op requires that the assigned value's type matches the
300/// assigned-to variable type.
301LogicalResult emitc::AssignOp::verify() {
303
304 if (!variable.getDefiningOp())
305 return emitOpError() << "cannot assign to block argument";
306
307 Type valueType = getValue().getType();
308 Type variableType = variable.getType().getValueType();
309 if (variableType != valueType)
310 return emitOpError() << "requires value's type (" << valueType
311 << ") to match variable's type (" << variableType
312 << ")\n variable: " << variable
313 << "\n value: " << getValue() << "\n";
314 return success();
315}
316
317//===----------------------------------------------------------------------===//
318// CastOp
319//===----------------------------------------------------------------------===//
320
321bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
322 Type input = inputs.front(), output = outputs.front();
323
324 if (auto arrayType = dyn_cast<emitc::ArrayType>(input)) {
325 if (auto pointerType = dyn_cast<emitc::PointerType>(output)) {
326 return (arrayType.getElementType() == pointerType.getPointee()) &&
327 arrayType.getShape().size() == 1 && arrayType.getShape()[0] >= 1;
328 }
329 return false;
330 }
331
332 return (
334 emitc::isSupportedFloatType(input) || isa<emitc::PointerType>(input)) &&
336 emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output)));
337}
338
339//===----------------------------------------------------------------------===//
340// CallOpaqueOp
341//===----------------------------------------------------------------------===//
342
343LogicalResult emitc::CallOpaqueOp::verify() {
344 // Callee must not be empty.
345 if (getCallee().empty())
346 return emitOpError("callee must not be empty");
347
348 if (std::optional<ArrayAttr> argsAttr = getArgs()) {
349 for (Attribute arg : *argsAttr) {
350 auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
351 if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {
352 int64_t index = intAttr.getInt();
353 // Args with elements of type index must be in range
354 // [0..operands.size).
355 if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands())))
356 return emitOpError("index argument is out of range");
357
358 // Args with elements of type ArrayAttr must have a type.
359 } else if (llvm::isa<ArrayAttr>(
360 arg) /*&& llvm::isa<NoneType>(arg.getType())*/) {
361 // FIXME: Array attributes never have types
362 return emitOpError("array argument has no type");
363 }
364 }
365 }
366
367 if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
368 for (Attribute tArg : *templateArgsAttr) {
369 if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
370 return emitOpError("template argument has invalid type");
371 }
372 }
373
374 if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {
375 return emitOpError() << "cannot return array type";
376 }
377
378 return success();
379}
380
381//===----------------------------------------------------------------------===//
382// ConstantOp
383//===----------------------------------------------------------------------===//
384
385LogicalResult emitc::ConstantOp::verify() {
386 Attribute value = getValueAttr();
387 if (failed(verifyInitializationAttribute(getOperation(), value)))
388 return failure();
389 if (auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) {
390 if (opaqueValue.getValue().empty())
391 return emitOpError() << "value must not be empty";
392 }
393 return success();
394}
395
396OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }
397
398//===----------------------------------------------------------------------===//
399// DereferenceOp
400//===----------------------------------------------------------------------===//
401
402LogicalResult DereferenceOp::verify() {
403 emitc::PointerType pointerType = getPointer().getType();
404
405 if (pointerType.getPointee() != getResult().getType().getValueType())
406 return emitOpError("requires result to be an lvalue of the type "
407 "pointed to by operand");
408
409 return success();
410}
411
412//===----------------------------------------------------------------------===//
413// ExpressionOp
414//===----------------------------------------------------------------------===//
415
416namespace {
417
418struct RemoveRecurringExpressionOperands
419 : public OpRewritePattern<ExpressionOp> {
420 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
421 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
422 PatternRewriter &rewriter) const override {
423 SetVector<Value> uniqueOperands;
424 DenseMap<Value, int> firstIndexOf;
425
426 // Collect duplicate operands and prepare to remove excessive copies.
427 for (auto [i, operand] : llvm::enumerate(expressionOp.getDefs())) {
428 if (uniqueOperands.contains(operand))
429 continue;
430 uniqueOperands.insert(operand);
431 firstIndexOf[operand] = i;
432 }
433
434 // If every operand is unique, bail out.
435 if (uniqueOperands.size() == expressionOp.getDefs().size())
436 return failure();
437
438 // Create a new expression with unique operands.
439 rewriter.setInsertionPointAfter(expressionOp);
440 auto uniqueExpression = emitc::ExpressionOp::create(
441 rewriter, expressionOp.getLoc(), expressionOp.getResult().getType(),
442 uniqueOperands.getArrayRef(), expressionOp.getDoNotInline());
443 Block &uniqueExpressionBody = uniqueExpression.createBody();
444
445 // Map each original block arguments to the unique block argument taking
446 // the same operand.
447 IRMapping mapper;
448 Block *expressionBody = expressionOp.getBody();
449 for (auto [operand, arg] :
450 llvm::zip(expressionOp.getOperands(), expressionBody->getArguments()))
451 mapper.map(arg, uniqueExpressionBody.getArgument(firstIndexOf[operand]));
452
453 rewriter.setInsertionPointToStart(&uniqueExpressionBody);
454 for (Operation &opToClone : *expressionOp.getBody())
455 rewriter.clone(opToClone, mapper);
456
457 // Complete the rewrite.
458 rewriter.replaceOp(expressionOp, uniqueExpression);
459
460 return success();
461 }
462};
463
464/// If an ExpressionOp body yields a block argument directly (no root op),
465/// this means a contained op was folded away (e.g., an identity cast whose
466/// in/out types match). Canonicalize by replacing the expression with the
467/// corresponding operand value.
468struct FoldTrivialExpressionOp : public OpRewritePattern<ExpressionOp> {
469 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
470 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
471 PatternRewriter &rewriter) const override {
472 auto yieldOp = cast<YieldOp>(expressionOp.getBody()->getTerminator());
473 Value yieldedValue = yieldOp.getResult();
474 auto blockArg = dyn_cast_if_present<BlockArgument>(yieldedValue);
475 if (!blockArg)
476 return failure();
477 rewriter.replaceOp(expressionOp,
478 expressionOp.getOperand(blockArg.getArgNumber()));
479 return success();
480 }
481};
482
483} // namespace
484
485void ExpressionOp::getCanonicalizationPatterns(RewritePatternSet &results,
486 MLIRContext *context) {
487 results.add<RemoveRecurringExpressionOperands, FoldTrivialExpressionOp>(
488 context);
489}
490
491ParseResult ExpressionOp::parse(OpAsmParser &parser, OperationState &result) {
493 if (parser.parseOperandList(operands))
494 return parser.emitError(parser.getCurrentLocation()) << "expected operands";
495 if (succeeded(parser.parseOptionalKeyword("noinline")))
496 result.addAttribute(ExpressionOp::getDoNotInlineAttrName(result.name),
497 parser.getBuilder().getUnitAttr());
498 Type type;
499 if (parser.parseColonType(type))
500 return parser.emitError(parser.getCurrentLocation(),
501 "expected function type");
502 auto fnType = llvm::dyn_cast<FunctionType>(type);
503 if (!fnType)
504 return parser.emitError(parser.getCurrentLocation(),
505 "expected function type");
506 if (parser.resolveOperands(operands, fnType.getInputs(),
507 parser.getCurrentLocation(), result.operands))
508 return failure();
509 if (fnType.getNumResults() != 1)
510 return parser.emitError(parser.getCurrentLocation(),
511 "expected single return type");
512 result.addTypes(fnType.getResults());
513 Region *body = result.addRegion();
514 DenseSet<Value> uniqueOperands(result.operands.begin(),
515 result.operands.end());
516 bool enableNameShadowing = uniqueOperands.size() == result.operands.size();
518 if (enableNameShadowing) {
519 for (auto [unresolvedOperand, operandType] :
520 llvm::zip(operands, fnType.getInputs())) {
521 OpAsmParser::Argument argInfo;
522 argInfo.ssaName = unresolvedOperand;
523 argInfo.type = operandType;
524 argsInfo.push_back(argInfo);
525 }
526 }
527 SMLoc beforeRegionLoc = parser.getCurrentLocation();
528 if (parser.parseRegion(*body, argsInfo, enableNameShadowing))
529 return failure();
530 if (!enableNameShadowing) {
531 if (body->front().getArguments().size() < result.operands.size()) {
532 return parser.emitError(
533 beforeRegionLoc, "with recurring operands expected block arguments");
534 }
535 }
536 return success();
537}
538
539void emitc::ExpressionOp::print(OpAsmPrinter &p) {
540 p << ' ';
541 auto operands = getDefs();
542 p.printOperands(operands);
543 p << " : ";
544 p.printFunctionalType(getOperation());
545 DenseSet<Value> uniqueOperands(operands.begin(), operands.end());
546 bool printEntryBlockArgs = true;
547 if (uniqueOperands.size() == operands.size()) {
548 p.shadowRegionArgs(getRegion(), getDefs());
549 printEntryBlockArgs = false;
550 }
551 p << ' ';
552 p.printRegion(getRegion(), printEntryBlockArgs);
553}
554
555Operation *ExpressionOp::getRootOp() {
556 auto yieldOp = cast<YieldOp>(getBody()->getTerminator());
557 Value yieldedValue = yieldOp.getResult();
558 return yieldedValue.getDefiningOp();
559}
560
561LogicalResult ExpressionOp::verify() {
562 Type resultType = getResult().getType();
563 Region &region = getRegion();
564
565 Block &body = region.front();
566
567 if (!body.mightHaveTerminator())
568 return emitOpError("must yield a value at termination");
569
570 auto yield = cast<YieldOp>(body.getTerminator());
571 Value yieldResult = yield.getResult();
572
573 if (!yieldResult)
574 return emitOpError("must yield a value at termination");
575
576 Operation *rootOp = yieldResult.getDefiningOp();
577
578 if (!rootOp)
579 return emitOpError("yielded value has no defining op");
580
581 if (rootOp->getParentOp() != getOperation())
582 return emitOpError("yielded value not defined within expression");
583
584 Type yieldType = yieldResult.getType();
585
586 if (resultType != yieldType)
587 return emitOpError("requires yielded type to match return type");
588
589 for (Operation &op : region.front().without_terminator()) {
590 auto expressionInterface = dyn_cast<emitc::CExpressionInterface>(op);
591 if (!expressionInterface)
592 return emitOpError("contains an unsupported operation");
593 if (op.getNumResults() != 1)
594 return emitOpError("requires exactly one result for each operation");
595 Value result = op.getResult(0);
596 if (result.use_empty())
597 return emitOpError("contains an unused operation");
598 }
599
600 // Make sure any operation with side effect is only reachable once from
601 // the root op, otherwise emission will be replicating side effects.
604 worklist.push_back(rootOp);
605 while (!worklist.empty()) {
606 Operation *op = worklist.back();
607 worklist.pop_back();
608 if (visited.contains(op)) {
609 if (cast<CExpressionInterface>(op).hasSideEffects())
610 return emitOpError(
611 "requires exactly one use for operations with side effects");
612 }
613 visited.insert(op);
614 for (Value operand : op->getOperands())
615 if (Operation *def = operand.getDefiningOp()) {
616 worklist.push_back(def);
617 }
618 }
619
620 return success();
621}
622
623//===----------------------------------------------------------------------===//
624// ForOp
625//===----------------------------------------------------------------------===//
626
627void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
628 Value ub, Value step, BodyBuilderFn bodyBuilder) {
629 OpBuilder::InsertionGuard g(builder);
630 result.addOperands({lb, ub, step});
631 Type t = lb.getType();
632 Region *bodyRegion = result.addRegion();
633 Block *bodyBlock = builder.createBlock(bodyRegion);
634 bodyBlock->addArgument(t, result.location);
635
636 // Create the default terminator if the builder is not provided.
637 if (!bodyBuilder) {
638 ForOp::ensureTerminator(*bodyRegion, builder, result.location);
639 } else {
640 OpBuilder::InsertionGuard guard(builder);
641 builder.setInsertionPointToStart(bodyBlock);
642 bodyBuilder(builder, result.location, bodyBlock->getArgument(0));
643 }
644}
645
646void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}
647
648ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
649 Builder &builder = parser.getBuilder();
650 Type type;
651
652 OpAsmParser::Argument inductionVariable;
654
655 // Parse the induction variable followed by '='.
656 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
657 // Parse loop bounds.
658 parser.parseOperand(lb) || parser.parseKeyword("to") ||
659 parser.parseOperand(ub) || parser.parseKeyword("step") ||
660 parser.parseOperand(step))
661 return failure();
662
663 // Parse the optional initial iteration arguments.
665 regionArgs.push_back(inductionVariable);
666
667 // Parse optional type, else assume Index.
668 if (parser.parseOptionalColon())
669 type = builder.getIndexType();
670 else if (parser.parseType(type))
671 return failure();
672
673 // Resolve input operands.
674 regionArgs.front().type = type;
675 if (parser.resolveOperand(lb, type, result.operands) ||
676 parser.resolveOperand(ub, type, result.operands) ||
677 parser.resolveOperand(step, type, result.operands))
678 return failure();
679
680 // Parse the body region.
681 Region *body = result.addRegion();
682 if (parser.parseRegion(*body, regionArgs))
683 return failure();
684
685 ForOp::ensureTerminator(*body, builder, result.location);
686
687 // Parse the optional attribute list.
688 if (parser.parseOptionalAttrDict(result.attributes))
689 return failure();
690
691 return success();
692}
693
694void ForOp::print(OpAsmPrinter &p) {
695 p << " " << getInductionVar() << " = " << getLowerBound() << " to "
696 << getUpperBound() << " step " << getStep();
697
698 p << ' ';
699 if (Type t = getInductionVar().getType(); !t.isIndex())
700 p << " : " << t << ' ';
701 p.printRegion(getRegion(),
702 /*printEntryBlockArgs=*/false,
703 /*printBlockTerminators=*/false);
704 p.printOptionalAttrDict((*this)->getAttrs());
705}
706
707LogicalResult ForOp::verifyRegions() {
708 // Check that the body defines as single block argument for the induction
709 // variable.
710 if (getBody()->getNumArguments() != 1)
711 return emitOpError("expected body to have a single block argument for the "
712 "induction variable");
713
714 if (getInductionVar().getType() != getLowerBound().getType())
715 return emitOpError(
716 "expected induction variable to be same type as bounds and step");
717
718 return success();
719}
720
721//===----------------------------------------------------------------------===//
722// CallOp
723//===----------------------------------------------------------------------===//
724
725LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
726 // Check that the callee attribute was specified.
727 auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");
728 if (!fnAttr)
729 return emitOpError("requires a 'callee' symbol reference attribute");
730 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
731 if (!fn)
732 return emitOpError() << "'" << fnAttr.getValue()
733 << "' does not reference a valid function";
734
735 // Verify that the operand and result types match the callee.
736 auto fnType = fn.getFunctionType();
737 if (fnType.getNumInputs() != getNumOperands())
738 return emitOpError("incorrect number of operands for callee");
739
740 for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)
741 if (getOperand(i).getType() != fnType.getInput(i))
742 return emitOpError("operand type mismatch: expected operand type ")
743 << fnType.getInput(i) << ", but provided "
744 << getOperand(i).getType() << " for operand number " << i;
745
746 if (fnType.getNumResults() != getNumResults())
747 return emitOpError("incorrect number of results for callee");
748
749 for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)
750 if (getResult(i).getType() != fnType.getResult(i)) {
751 auto diag = emitOpError("result type mismatch at index ") << i;
752 diag.attachNote() << " op result types: " << getResultTypes();
753 diag.attachNote() << "function result types: " << fnType.getResults();
754 return diag;
755 }
756
757 return success();
758}
759
760FunctionType CallOp::getCalleeType() {
761 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
762}
763
764//===----------------------------------------------------------------------===//
765// DeclareFuncOp
766//===----------------------------------------------------------------------===//
767
768LogicalResult
769DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
770 // Check that the sym_name attribute was specified.
771 auto fnAttr = getSymNameAttr();
772 if (!fnAttr)
773 return emitOpError("requires a 'sym_name' symbol reference attribute");
774 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
775 if (!fn)
776 return emitOpError() << "'" << fnAttr.getValue()
777 << "' does not reference a valid function";
778
779 return success();
780}
781
782//===----------------------------------------------------------------------===//
783// FuncOp
784//===----------------------------------------------------------------------===//
785
786void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
787 FunctionType type, ArrayRef<NamedAttribute> attrs,
788 ArrayRef<DictionaryAttr> argAttrs) {
790 builder.getStringAttr(name));
791 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
792 state.attributes.append(attrs.begin(), attrs.end());
793 state.addRegion();
794
795 if (argAttrs.empty())
796 return;
797 assert(type.getNumInputs() == argAttrs.size());
799 builder, state, argAttrs, /*resultAttrs=*/{},
800 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
801}
802
803ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
804 auto buildFuncType =
805 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
807 std::string &) { return builder.getFunctionType(argTypes, results); };
808
810 parser, result, /*allowVariadic=*/false,
811 getFunctionTypeAttrName(result.name), buildFuncType,
812 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
813}
814
815void FuncOp::print(OpAsmPrinter &p) {
817 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
818 getArgAttrsAttrName(), getResAttrsAttrName());
819}
820
821LogicalResult FuncOp::verify() {
822 if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {
823 return emitOpError("cannot have lvalue type as argument");
824 }
825
826 if (getNumResults() > 1)
827 return emitOpError("requires zero or exactly one result, but has ")
828 << getNumResults();
829
830 if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
831 return emitOpError("cannot return array type");
832
833 return success();
834}
835
836//===----------------------------------------------------------------------===//
837// ReturnOp
838//===----------------------------------------------------------------------===//
839
840LogicalResult ReturnOp::verify() {
841 auto function = cast<FuncOp>((*this)->getParentOp());
842
843 // The operand number and types must match the function signature.
844 if (getNumOperands() != function.getNumResults())
845 return emitOpError("has ")
846 << getNumOperands() << " operands, but enclosing function (@"
847 << function.getName() << ") returns " << function.getNumResults();
848
849 if (function.getNumResults() == 1)
850 if (getOperand().getType() != function.getResultTypes()[0])
851 return emitError() << "type of the return operand ("
852 << getOperand().getType()
853 << ") doesn't match function result type ("
854 << function.getResultTypes()[0] << ")"
855 << " in function @" << function.getName();
856 return success();
857}
858
859//===----------------------------------------------------------------------===//
860// IfOp
861//===----------------------------------------------------------------------===//
862
863void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
864 bool addThenBlock, bool addElseBlock) {
865 assert((!addElseBlock || addThenBlock) &&
866 "must not create else block w/o then block");
867 result.addOperands(cond);
868
869 // Add regions and blocks.
870 OpBuilder::InsertionGuard guard(builder);
871 Region *thenRegion = result.addRegion();
872 if (addThenBlock)
873 builder.createBlock(thenRegion);
874 Region *elseRegion = result.addRegion();
875 if (addElseBlock)
876 builder.createBlock(elseRegion);
877}
878
879void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
880 bool withElseRegion) {
881 result.addOperands(cond);
882
883 // Build then region.
884 OpBuilder::InsertionGuard guard(builder);
885 Region *thenRegion = result.addRegion();
886 builder.createBlock(thenRegion);
887
888 // Build else region.
889 Region *elseRegion = result.addRegion();
890 if (withElseRegion) {
891 builder.createBlock(elseRegion);
892 }
893}
894
895void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
896 function_ref<void(OpBuilder &, Location)> thenBuilder,
897 function_ref<void(OpBuilder &, Location)> elseBuilder) {
898 assert(thenBuilder && "the builder callback for 'then' must be present");
899 result.addOperands(cond);
900
901 // Build then region.
902 OpBuilder::InsertionGuard guard(builder);
903 Region *thenRegion = result.addRegion();
904 builder.createBlock(thenRegion);
905 thenBuilder(builder, result.location);
906
907 // Build else region.
908 Region *elseRegion = result.addRegion();
909 if (elseBuilder) {
910 builder.createBlock(elseRegion);
911 elseBuilder(builder, result.location);
912 }
913}
914
915ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) {
916 // Create the regions for 'then'.
917 result.regions.reserve(2);
918 Region *thenRegion = result.addRegion();
919 Region *elseRegion = result.addRegion();
920
921 Builder &builder = parser.getBuilder();
923 Type i1Type = builder.getIntegerType(1);
924 if (parser.parseOperand(cond) ||
925 parser.resolveOperand(cond, i1Type, result.operands))
926 return failure();
927 // Parse the 'then' region.
928 if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))
929 return failure();
930 IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
931
932 // If we find an 'else' keyword then parse the 'else' region.
933 if (!parser.parseOptionalKeyword("else")) {
934 if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))
935 return failure();
936 IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
937 }
938
939 // Parse the optional attribute list.
940 if (parser.parseOptionalAttrDict(result.attributes))
941 return failure();
942 return success();
943}
944
945void IfOp::print(OpAsmPrinter &p) {
946 bool printBlockTerminators = false;
947
948 p << " " << getCondition();
949 p << ' ';
950 p.printRegion(getThenRegion(),
951 /*printEntryBlockArgs=*/false,
952 /*printBlockTerminators=*/printBlockTerminators);
953
954 // Print the 'else' regions if it exists and has a block.
955 Region &elseRegion = getElseRegion();
956 if (!elseRegion.empty()) {
957 p << " else ";
958 p.printRegion(elseRegion,
959 /*printEntryBlockArgs=*/false,
960 /*printBlockTerminators=*/printBlockTerminators);
961 }
962
963 p.printOptionalAttrDict((*this)->getAttrs());
964}
965
966/// Given the region at `index`, or the parent operation if `index` is None,
967/// return the successor regions. These are the regions that may be selected
968/// during the flow of control. `operands` is a set of optional attributes
969/// that correspond to a constant value for each operand, or null if that
970/// operand is not a constant.
971void IfOp::getSuccessorRegions(RegionBranchPoint point,
973 // The `then` and the `else` region branch back to the parent operation.
974 if (!point.isParent()) {
975 regions.push_back(RegionSuccessor::parent());
976 return;
977 }
978
979 regions.push_back(RegionSuccessor(&getThenRegion()));
980
981 // Don't consider the else region if it is empty.
982 Region *elseRegion = &this->getElseRegion();
983 if (elseRegion->empty())
984 regions.push_back(RegionSuccessor::parent());
985 else
986 regions.push_back(RegionSuccessor(elseRegion));
987}
988
989ValueRange IfOp::getSuccessorInputs(RegionSuccessor successor) {
990 return successor.isParent() ? ValueRange(getOperation()->getResults())
991 : ValueRange();
992}
993
994void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,
996 FoldAdaptor adaptor(operands, *this);
997 auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
998 if (!boolAttr || boolAttr.getValue())
999 regions.emplace_back(&getThenRegion());
1000
1001 // If the else region is empty, execution continues after the parent op.
1002 if (!boolAttr || !boolAttr.getValue()) {
1003 if (!getElseRegion().empty())
1004 regions.emplace_back(&getElseRegion());
1005 else
1006 regions.emplace_back(RegionSuccessor::parent());
1007 }
1008}
1009
1010void IfOp::getRegionInvocationBounds(
1011 ArrayRef<Attribute> operands,
1012 SmallVectorImpl<InvocationBounds> &invocationBounds) {
1013 if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
1014 // If the condition is known, then one region is known to be executed once
1015 // and the other zero times.
1016 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
1017 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
1018 } else {
1019 // Non-constant condition. Each region may be executed 0 or 1 times.
1020 invocationBounds.assign(2, {0, 1});
1021 }
1022}
1023
1024//===----------------------------------------------------------------------===//
1025// IncludeOp
1026//===----------------------------------------------------------------------===//
1027
1028void IncludeOp::print(OpAsmPrinter &p) {
1029 bool standardInclude = getIsStandardInclude();
1030
1031 p << " ";
1032 if (standardInclude)
1033 p << "<";
1034 p << "\"" << getInclude() << "\"";
1035 if (standardInclude)
1036 p << ">";
1037}
1038
1039ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {
1040 bool standardInclude = !parser.parseOptionalLess();
1041
1042 StringAttr include;
1043 OptionalParseResult includeParseResult =
1044 parser.parseOptionalAttribute(include, "include", result.attributes);
1045 if (!includeParseResult.has_value())
1046 return parser.emitError(parser.getNameLoc()) << "expected string attribute";
1047
1048 if (standardInclude && parser.parseOptionalGreater())
1049 return parser.emitError(parser.getNameLoc())
1050 << "expected trailing '>' for standard include";
1051
1052 if (standardInclude)
1053 result.addAttribute("is_standard_include",
1054 UnitAttr::get(parser.getContext()));
1055
1056 return success();
1057}
1058
1059//===----------------------------------------------------------------------===//
1060// LiteralOp
1061//===----------------------------------------------------------------------===//
1062
1063/// The literal op requires a non-empty value.
1064LogicalResult emitc::LiteralOp::verify() {
1065 if (getValue().empty())
1066 return emitOpError() << "value must not be empty";
1067 return success();
1068}
1069//===----------------------------------------------------------------------===//
1070// SubOp
1071//===----------------------------------------------------------------------===//
1072
1073LogicalResult SubOp::verify() {
1074 Type lhsType = getLhs().getType();
1075 Type rhsType = getRhs().getType();
1076 Type resultType = getResult().getType();
1077
1078 if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
1079 return emitOpError("rhs can only be a pointer if lhs is a pointer");
1080
1081 if (isa<emitc::PointerType>(lhsType) &&
1082 !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
1083 return emitOpError("requires that rhs is an integer, pointer or of opaque "
1084 "type if lhs is a pointer");
1085
1086 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
1087 !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))
1088 return emitOpError("requires that the result is an integer, ptrdiff_t or "
1089 "of opaque type if lhs and rhs are pointers");
1090 return success();
1091}
1092
1093//===----------------------------------------------------------------------===//
1094// VariableOp
1095//===----------------------------------------------------------------------===//
1096
1097LogicalResult emitc::VariableOp::verify() {
1098 return verifyInitializationAttribute(getOperation(), getValueAttr());
1099}
1100
1101//===----------------------------------------------------------------------===//
1102// YieldOp
1103//===----------------------------------------------------------------------===//
1104
1105LogicalResult emitc::YieldOp::verify() {
1106 Value result = getResult();
1107 Operation *containingOp = getOperation()->getParentOp();
1108
1109 if (!isa<DoOp>(containingOp) && result && containingOp->getNumResults() != 1)
1110 return emitOpError() << "yields a value not returned by parent";
1111
1112 if (!isa<DoOp>(containingOp) && !result && containingOp->getNumResults() != 0)
1113 return emitOpError() << "does not yield a value to be returned by parent";
1114
1115 return success();
1116}
1117
1118//===----------------------------------------------------------------------===//
1119// SubscriptOp
1120//===----------------------------------------------------------------------===//
1121
1122LogicalResult emitc::SubscriptOp::verify() {
1123 // Checks for array operand.
1124 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {
1125 // Check number of indices.
1126 if (getIndices().size() != (size_t)arrayType.getRank()) {
1127 return emitOpError() << "on array operand requires number of indices ("
1128 << getIndices().size()
1129 << ") to match the rank of the array type ("
1130 << arrayType.getRank() << ")";
1131 }
1132 // Check types of index operands.
1133 for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {
1134 Type type = getIndices()[i].getType();
1135 if (!isIntegerIndexOrOpaqueType(type)) {
1136 return emitOpError() << "on array operand requires index operand " << i
1137 << " to be integer-like, but got " << type;
1138 }
1139 }
1140 // Check element type.
1141 Type elementType = arrayType.getElementType();
1142 Type resultType = getType().getValueType();
1143 if (elementType != resultType) {
1144 return emitOpError() << "on array operand requires element type ("
1145 << elementType << ") and result type (" << resultType
1146 << ") to match";
1147 }
1148 return success();
1149 }
1150
1151 // Checks for pointer operand.
1152 if (auto pointerType =
1153 llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {
1154 // Check number of indices.
1155 if (getIndices().size() != 1) {
1156 return emitOpError()
1157 << "on pointer operand requires one index operand, but got "
1158 << getIndices().size();
1159 }
1160 // Check types of index operand.
1161 Type type = getIndices()[0].getType();
1162 if (!isIntegerIndexOrOpaqueType(type)) {
1163 return emitOpError() << "on pointer operand requires index operand to be "
1164 "integer-like, but got "
1165 << type;
1166 }
1167 // Check pointee type.
1168 Type pointeeType = pointerType.getPointee();
1169 Type resultType = getType().getValueType();
1170 if (pointeeType != resultType) {
1171 return emitOpError() << "on pointer operand requires pointee type ("
1172 << pointeeType << ") and result type (" << resultType
1173 << ") to match";
1174 }
1175 return success();
1176 }
1177
1178 // The operand has opaque type, so we can't assume anything about the number
1179 // or types of index operands.
1180 return success();
1181}
1182
1183//===----------------------------------------------------------------------===//
1184// VerbatimOp
1185//===----------------------------------------------------------------------===//
1186
1187LogicalResult emitc::VerbatimOp::verify() {
1188 auto errorCallback = [&]() -> InFlightDiagnostic {
1189 return this->emitOpError();
1190 };
1191 FailureOr<SmallVector<ReplacementItem>> fmt =
1192 ::parseFormatString(getValue(), getFmtArgs(), errorCallback);
1193 if (failed(fmt))
1194 return failure();
1195
1196 size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) {
1197 return std::holds_alternative<Placeholder>(item);
1198 });
1199
1200 if (numPlaceholders != getFmtArgs().size()) {
1201 return emitOpError()
1202 << "requires operands for each placeholder in the format string";
1203 }
1204 return success();
1205}
1206
1207FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {
1208 // Error checking is done in verify.
1209 return ::parseFormatString(getValue(), getFmtArgs());
1210}
1211
1212//===----------------------------------------------------------------------===//
1213// EmitC Enums
1214//===----------------------------------------------------------------------===//
1215
1216#include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
1217
1218//===----------------------------------------------------------------------===//
1219// EmitC Attributes
1220//===----------------------------------------------------------------------===//
1221
1222#define GET_ATTRDEF_CLASSES
1223#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
1224
1225//===----------------------------------------------------------------------===//
1226// EmitC Types
1227//===----------------------------------------------------------------------===//
1228
1229#define GET_TYPEDEF_CLASSES
1230#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
1231
1232//===----------------------------------------------------------------------===//
1233// ArrayType
1234//===----------------------------------------------------------------------===//
1235
1236Type emitc::ArrayType::parse(AsmParser &parser) {
1237 if (parser.parseLess())
1238 return Type();
1239
1240 SmallVector<int64_t, 4> dimensions;
1241 if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,
1242 /*withTrailingX=*/true))
1243 return Type();
1244 // Parse the element type.
1245 auto typeLoc = parser.getCurrentLocation();
1246 Type elementType;
1247 if (parser.parseType(elementType))
1248 return Type();
1249
1250 // Check that array is formed from allowed types.
1251 if (!isValidElementType(elementType))
1252 return parser.emitError(typeLoc, "invalid array element type '")
1253 << elementType << "'",
1254 Type();
1255 if (parser.parseGreater())
1256 return Type();
1257 return parser.getChecked<ArrayType>(dimensions, elementType);
1258}
1259
1260void emitc::ArrayType::print(AsmPrinter &printer) const {
1261 printer << "<";
1262 for (int64_t dim : getShape()) {
1263 printer << dim << 'x';
1264 }
1265 printer.printType(getElementType());
1266 printer << ">";
1267}
1268
1269LogicalResult emitc::ArrayType::verify(
1271 ::llvm::ArrayRef<int64_t> shape, Type elementType) {
1272 if (shape.empty())
1273 return emitError() << "shape must not be empty";
1274
1275 for (int64_t dim : shape) {
1276 if (dim < 0)
1277 return emitError() << "dimensions must have non-negative size";
1278 }
1279
1280 if (!elementType)
1281 return emitError() << "element type must not be none";
1282
1283 if (!isValidElementType(elementType))
1284 return emitError() << "invalid array element type";
1285
1286 return success();
1287}
1288
1289emitc::ArrayType
1290emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
1291 Type elementType) const {
1292 if (!shape)
1293 return emitc::ArrayType::get(getShape(), elementType);
1294 return emitc::ArrayType::get(*shape, elementType);
1295}
1296
1297//===----------------------------------------------------------------------===//
1298// LValueType
1299//===----------------------------------------------------------------------===//
1300
1301LogicalResult mlir::emitc::LValueType::verify(
1303 mlir::Type value) {
1304 // Check that the wrapped type is valid. This especially forbids nested
1305 // lvalue types.
1306 if (!isSupportedEmitCType(value))
1307 return emitError()
1308 << "!emitc.lvalue must wrap supported emitc type, but got " << value;
1309
1310 if (llvm::isa<emitc::ArrayType>(value))
1311 return emitError() << "!emitc.lvalue cannot wrap !emitc.array type";
1312
1313 return success();
1314}
1315
1316//===----------------------------------------------------------------------===//
1317// OpaqueType
1318//===----------------------------------------------------------------------===//
1319
1320LogicalResult mlir::emitc::OpaqueType::verify(
1322 llvm::StringRef value) {
1323 if (value.empty()) {
1324 return emitError() << "expected non empty string in !emitc.opaque type";
1325 }
1326 if (value.back() == '*') {
1327 return emitError() << "pointer not allowed as outer type with "
1328 "!emitc.opaque, use !emitc.ptr instead";
1329 }
1330 return success();
1331}
1332
1333//===----------------------------------------------------------------------===//
1334// PointerType
1335//===----------------------------------------------------------------------===//
1336
1337LogicalResult mlir::emitc::PointerType::verify(
1339 if (llvm::isa<emitc::LValueType>(value))
1340 return emitError() << "pointers to lvalues are not allowed";
1341
1342 return success();
1343}
1344
1345//===----------------------------------------------------------------------===//
1346// GlobalOp
1347//===----------------------------------------------------------------------===//
1349 TypeAttr type,
1350 Attribute initialValue) {
1351 p << type;
1352 if (initialValue) {
1353 p << " = ";
1354 p.printAttributeWithoutType(initialValue);
1355 }
1356}
1357
1359 if (auto array = llvm::dyn_cast<ArrayType>(type))
1360 return RankedTensorType::get(array.getShape(), array.getElementType());
1361 return type;
1362}
1363
1364static ParseResult
1366 Attribute &initialValue) {
1367 Type type;
1368 if (parser.parseType(type))
1369 return failure();
1370
1371 typeAttr = TypeAttr::get(type);
1372
1373 if (parser.parseOptionalEqual())
1374 return success();
1375
1376 if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))
1377 return failure();
1378
1379 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1380 initialValue))
1381 return parser.emitError(parser.getNameLoc())
1382 << "initial value should be a integer, float, elements or opaque "
1383 "attribute";
1384 return success();
1385}
1386
1387LogicalResult GlobalOp::verify() {
1388 if (!isSupportedEmitCType(getType())) {
1389 return emitOpError("expected valid emitc type");
1390 }
1391 if (getInitialValue().has_value()) {
1392 Attribute initValue = getInitialValue().value();
1393 // Check that the type of the initial value is compatible with the type of
1394 // the global variable.
1395 if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1396 auto arrayType = llvm::dyn_cast<ArrayType>(getType());
1397 if (!arrayType)
1398 return emitOpError("expected array type, but got ") << getType();
1399
1400 Type initType = elementsAttr.getType();
1402 if (initType != tensorType) {
1403 return emitOpError("initial value expected to be of type ")
1404 << getType() << ", but was of type " << initType;
1405 }
1406 } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1407 if (intAttr.getType() != getType()) {
1408 return emitOpError("initial value expected to be of type ")
1409 << getType() << ", but was of type " << intAttr.getType();
1410 }
1411 } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1412 if (floatAttr.getType() != getType()) {
1413 return emitOpError("initial value expected to be of type ")
1414 << getType() << ", but was of type " << floatAttr.getType();
1415 }
1416 } else if (!isa<emitc::OpaqueAttr>(initValue)) {
1417 return emitOpError("initial value should be a integer, float, elements "
1418 "or opaque attribute, but got ")
1419 << initValue;
1420 }
1421 }
1422 if (getStaticSpecifier() && getExternSpecifier()) {
1423 return emitOpError("cannot have both static and extern specifiers");
1424 }
1425 return success();
1426}
1427
1428//===----------------------------------------------------------------------===//
1429// GetGlobalOp
1430//===----------------------------------------------------------------------===//
1431
1432LogicalResult
1433GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1434 // Verify that the type matches the type of the global variable.
1435 auto global =
1436 symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1437 if (!global)
1438 return emitOpError("'")
1439 << getName() << "' does not reference a valid emitc.global";
1440
1441 Type resultType = getResult().getType();
1442 Type globalType = global.getType();
1443
1444 // global has array type
1445 if (llvm::isa<ArrayType>(globalType)) {
1446 if (globalType != resultType)
1447 return emitOpError("on array type expects result type ")
1448 << resultType << " to match type " << globalType
1449 << " of the global @" << getName();
1450 return success();
1451 }
1452
1453 // global has non-array type
1454 auto lvalueType = dyn_cast<LValueType>(resultType);
1455 if (!lvalueType)
1456 return emitOpError("on non-array type expects result type to be an "
1457 "lvalue type for the global @")
1458 << getName();
1459 if (lvalueType.getValueType() != globalType)
1460 return emitOpError("on non-array type expects result inner type ")
1461 << lvalueType.getValueType() << " to match type " << globalType
1462 << " of the global @" << getName();
1463 return success();
1464}
1465
1466//===----------------------------------------------------------------------===//
1467// SwitchOp
1468//===----------------------------------------------------------------------===//
1469
1470/// Parse the case regions and values.
1471static ParseResult
1473 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
1474 SmallVector<int64_t> caseValues;
1475 while (succeeded(parser.parseOptionalKeyword("case"))) {
1476 int64_t value;
1477 Region &region = *caseRegions.emplace_back(std::make_unique<Region>());
1478 if (parser.parseInteger(value) ||
1479 parser.parseRegion(region, /*arguments=*/{}))
1480 return failure();
1481 caseValues.push_back(value);
1482 }
1483 cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);
1484 return success();
1485}
1486
1487/// Print the case regions and values.
1489 DenseI64ArrayAttr cases, RegionRange caseRegions) {
1490 for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {
1491 p.printNewline();
1492 p << "case " << value << ' ';
1493 p.printRegion(*region, /*printEntryBlockArgs=*/false);
1494 }
1495}
1496
1497static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region,
1498 const Twine &name) {
1499 auto yield = dyn_cast<emitc::YieldOp>(region.front().back());
1500 if (!yield)
1501 return op.emitOpError("expected region to end with emitc.yield, but got ")
1502 << region.front().back().getName();
1503
1504 if (yield.getNumOperands() != 0) {
1505 return (op.emitOpError("expected each region to return ")
1506 << "0 values, but " << name << " returns "
1507 << yield.getNumOperands())
1508 .attachNote(yield.getLoc())
1509 << "see yield operation here";
1510 }
1511
1512 return success();
1513}
1514
1515LogicalResult emitc::SwitchOp::verify() {
1516 if (!isIntegerIndexOrOpaqueType(getArg().getType()))
1517 return emitOpError("unsupported type ") << getArg().getType();
1518
1519 if (getCases().size() != getCaseRegions().size()) {
1520 return emitOpError("has ")
1521 << getCaseRegions().size() << " case regions but "
1522 << getCases().size() << " case values";
1523 }
1524
1525 DenseSet<int64_t> valueSet;
1526 for (int64_t value : getCases())
1527 if (!valueSet.insert(value).second)
1528 return emitOpError("has duplicate case value: ") << value;
1529
1530 if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))
1531 return failure();
1532
1533 for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
1534 if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))
1535 return failure();
1536
1537 return success();
1538}
1539
1540unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }
1541
1542Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }
1543
1544Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {
1545 assert(idx < getNumCases() && "case index out-of-bounds");
1546 return getCaseRegions()[idx].front();
1547}
1548
1549void SwitchOp::getSuccessorRegions(
1551 llvm::append_range(successors, getRegions());
1552}
1553
1554void SwitchOp::getEntrySuccessorRegions(
1555 ArrayRef<Attribute> operands,
1557 FoldAdaptor adaptor(operands, *this);
1558
1559 // If a constant was not provided, all regions are possible successors.
1560 auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
1561 if (!arg) {
1562 llvm::append_range(successors, getRegions());
1563 return;
1564 }
1565
1566 // Otherwise, try to find a case with a matching value. If not, the
1567 // default region is the only successor.
1568 for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
1569 if (caseValue == arg.getInt()) {
1570 successors.emplace_back(&caseRegion);
1571 return;
1572 }
1573 }
1574 successors.emplace_back(&getDefaultRegion());
1575}
1576
1577void SwitchOp::getRegionInvocationBounds(
1579 auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
1580 if (!operandValue) {
1581 // All regions are invoked at most once.
1582 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1583 return;
1584 }
1585
1586 unsigned liveIndex = getNumRegions() - 1;
1587 const auto *iteratorToInt = llvm::find(getCases(), operandValue.getInt());
1588
1589 liveIndex = iteratorToInt != getCases().end()
1590 ? std::distance(getCases().begin(), iteratorToInt)
1591 : liveIndex;
1592
1593 for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
1594 ++regIndex)
1595 bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
1596}
1597
1598//===----------------------------------------------------------------------===//
1599// FileOp
1600//===----------------------------------------------------------------------===//
1601void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {
1602 state.addRegion()->emplaceBlock();
1603 state.attributes.push_back(
1604 builder.getNamedAttr("id", builder.getStringAttr(id)));
1605}
1606
1607//===----------------------------------------------------------------------===//
1608// FieldOp
1609//===----------------------------------------------------------------------===//
1610
1612 TypeAttr type,
1613 Attribute initialValue) {
1614 p << type;
1615 if (initialValue) {
1616 p << " = ";
1617 p.printAttributeWithoutType(initialValue);
1618 }
1619}
1620
1622 if (auto array = llvm::dyn_cast<ArrayType>(type))
1623 return RankedTensorType::get(array.getShape(), array.getElementType());
1624 return type;
1625}
1626
1627static ParseResult
1629 Attribute &initialValue) {
1630 Type type;
1631 if (parser.parseType(type))
1632 return failure();
1633
1634 typeAttr = TypeAttr::get(type);
1635
1636 if (parser.parseOptionalEqual())
1637 return success();
1638
1639 if (parser.parseAttribute(initialValue, getInitializerTypeForField(type)))
1640 return failure();
1641
1642 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1643 initialValue))
1644 return parser.emitError(parser.getNameLoc())
1645 << "initial value should be a integer, float, elements or opaque "
1646 "attribute";
1647 return success();
1648}
1649
1650LogicalResult FieldOp::verify() {
1652 return emitOpError("expected valid emitc type");
1653
1654 Operation *parentOp = getOperation()->getParentOp();
1655 if (!parentOp || !isa<emitc::ClassOp>(parentOp))
1656 return emitOpError("field must be nested within an emitc.class operation");
1657
1658 StringAttr symName = getSymNameAttr();
1659 if (!symName || symName.getValue().empty())
1660 return emitOpError("field must have a non-empty symbol name");
1661
1662 return success();
1663}
1664
1665//===----------------------------------------------------------------------===//
1666// GetFieldOp
1667//===----------------------------------------------------------------------===//
1668
1669LogicalResult GetFieldOp::verify() {
1670 auto parentClassOp = getOperation()->getParentOfType<emitc::ClassOp>();
1671 if (!parentClassOp.getOperation())
1672 return emitOpError(" must be nested within an emitc.class operation");
1673
1674 return success();
1675}
1676
1677LogicalResult GetFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1678 mlir::FlatSymbolRefAttr fieldNameAttr = getFieldNameAttr();
1679 FieldOp fieldOp =
1680 symbolTable.lookupNearestSymbolFrom<FieldOp>(*this, fieldNameAttr);
1681 if (!fieldOp)
1682 return emitOpError("field '")
1683 << fieldNameAttr << "' not found in the class";
1684
1685 Type getFieldResultType = getResult().getType();
1686 Type fieldType = fieldOp.getType();
1687
1688 if (fieldType != getFieldResultType)
1689 return emitOpError("result type ")
1690 << getFieldResultType << " does not match field '" << fieldNameAttr
1691 << "' type " << fieldType;
1692
1693 return success();
1694}
1695
1696//===----------------------------------------------------------------------===//
1697// DoOp
1698//===----------------------------------------------------------------------===//
1699
1700void DoOp::print(OpAsmPrinter &p) {
1701 p << ' ';
1702 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
1703 p << " while ";
1704 p.printRegion(getConditionRegion());
1705 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs());
1706}
1707
1708LogicalResult emitc::DoOp::verify() {
1709 Block &condBlock = getConditionRegion().front();
1710
1711 if (condBlock.getOperations().size() != 2)
1712 return emitOpError(
1713 "condition region must contain exactly two operations: "
1714 "'emitc.expression' followed by 'emitc.yield', but found ")
1715 << condBlock.getOperations().size() << " operations";
1716
1717 Operation &first = condBlock.front();
1718 auto exprOp = dyn_cast<emitc::ExpressionOp>(first);
1719 if (!exprOp)
1720 return emitOpError("expected first op in condition region to be "
1721 "'emitc.expression', but got ")
1722 << first.getName();
1723
1724 if (!exprOp.getResult().getType().isInteger(1))
1725 return emitOpError("emitc.expression in condition region must return "
1726 "'i1', but returns ")
1727 << exprOp.getResult().getType();
1728
1729 Operation &last = condBlock.back();
1730 auto condYield = dyn_cast<emitc::YieldOp>(last);
1731 if (!condYield)
1732 return emitOpError("expected last op in condition region to be "
1733 "'emitc.yield', but got ")
1734 << last.getName();
1735
1736 if (condYield.getNumOperands() != 1)
1737 return emitOpError("expected condition region to return 1 value, but "
1738 "it returns ")
1739 << condYield.getNumOperands() << " values";
1740
1741 if (condYield.getOperand(0) != exprOp.getResult())
1742 return emitError("'emitc.yield' must return result of "
1743 "'emitc.expression' from this condition region");
1744
1745 Block &bodyBlock = getBodyRegion().front();
1746 if (bodyBlock.mightHaveTerminator())
1747 return emitOpError("body region must not contain terminator");
1748
1749 return success();
1750}
1751
1752ParseResult DoOp::parse(OpAsmParser &parser, OperationState &result) {
1753 Region *bodyRegion = result.addRegion();
1754 Region *condRegion = result.addRegion();
1755
1756 if (parser.parseRegion(*bodyRegion) || parser.parseKeyword("while") ||
1757 parser.parseRegion(*condRegion))
1758 return failure();
1759
1760 if (bodyRegion->empty())
1761 bodyRegion->emplaceBlock();
1762
1763 return parser.parseOptionalAttrDictWithKeyword(result.attributes);
1764}
1765
1766//===----------------------------------------------------------------------===//
1767// TableGen'd op method definitions
1768//===----------------------------------------------------------------------===//
1769
1770#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"
1771
1772#define GET_OP_CLASSES
1773#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 bool hasSideEffects(Operation *op)
static LogicalResult verifyInitializationAttribute(Operation *op, Attribute value)
Check that the type of the initial value is compatible with the operations result type.
Definition EmitC.cpp:145
static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region, const Twine &name)
Definition EmitC.cpp:1497
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1365
static Type getInitializerTypeForField(Type type)
Definition EmitC.cpp:1621
static ParseResult parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1628
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:1348
static ParseResult parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, SmallVectorImpl< std::unique_ptr< Region > > &caseRegions)
Parse the case regions and values.
Definition EmitC.cpp:1472
static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op, TypeAttr type, Attribute initialValue)
Definition EmitC.cpp:1611
static void printSwitchCases(OpAsmPrinter &p, Operation *op, DenseI64ArrayAttr cases, RegionRange caseRegions)
Print the case regions and values.
Definition EmitC.cpp:1488
static Type getInitializerTypeForGlobal(Type type)
Definition EmitC.cpp:1358
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:773
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:139
OpListType & getOperations()
Definition Block.h:147
Operation & front()
Definition Block.h:163
Operation & back()
Definition Block.h:162
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:97
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:102
DenseI64ArrayAttr getDenseI64ArrayAttr(ArrayRef< int64_t > values)
Definition Builders.cpp:171
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition Builders.cpp:80
IntegerType getIntegerType(unsigned width)
Definition Builders.cpp:71
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:266
IndexType getIndexType()
Definition Builders.cpp:55
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition Builders.cpp:98
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:350
This class helps build Operations.
Definition Builders.h:209
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:434
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:566
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:433
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Definition Builders.h:414
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:88
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:436
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:255
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:119
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:407
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:433
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:357
This class represents a successor of a region.
static RegionSuccessor parent()
Initialize a successor that branches after/out of the parent operation.
bool isParent() const
Return true if the successor is the parent 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:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isIndex() const
Definition Types.cpp:56
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
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.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
Definition OpenACC.cpp:5049
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:305
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:120
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::SetVector< T, Vector, Set, N > SetVector
Definition LLVM.h:123
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:497
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:118
llvm::function_ref< Fn > function_ref
Definition LLVM.h:144
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.