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 auto cExpr = cast<CExpressionInterface>(op);
610 if (!cExpr.alwaysInline() && cExpr.hasSideEffects())
611 return emitOpError(
612 "requires exactly one use for operations with side effects");
613 }
614 visited.insert(op);
615 for (Value operand : op->getOperands())
616 if (Operation *def = operand.getDefiningOp()) {
617 worklist.push_back(def);
618 }
619 }
620
621 // It is illegal to forbid inlining of expressions whose root operation must
622 // be inlined.
623 if (getDoNotInline() &&
624 cast<emitc::CExpressionInterface>(rootOp).alwaysInline()) {
625 return emitOpError("root operation must be inlined but expression is marked"
626 " do-not-inline");
627 }
628
629 return success();
630}
631
632//===----------------------------------------------------------------------===//
633// ForOp
634//===----------------------------------------------------------------------===//
635
636void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
637 Value ub, Value step, BodyBuilderFn bodyBuilder) {
638 OpBuilder::InsertionGuard g(builder);
639 result.addOperands({lb, ub, step});
640 Type t = lb.getType();
641 Region *bodyRegion = result.addRegion();
642 Block *bodyBlock = builder.createBlock(bodyRegion);
643 bodyBlock->addArgument(t, result.location);
644
645 // Create the default terminator if the builder is not provided.
646 if (!bodyBuilder) {
647 ForOp::ensureTerminator(*bodyRegion, builder, result.location);
648 } else {
649 OpBuilder::InsertionGuard guard(builder);
650 builder.setInsertionPointToStart(bodyBlock);
651 bodyBuilder(builder, result.location, bodyBlock->getArgument(0));
652 }
653}
654
655void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}
656
657ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
658 Builder &builder = parser.getBuilder();
659 Type type;
660
661 OpAsmParser::Argument inductionVariable;
663
664 // Parse the induction variable followed by '='.
665 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
666 // Parse loop bounds.
667 parser.parseOperand(lb) || parser.parseKeyword("to") ||
668 parser.parseOperand(ub) || parser.parseKeyword("step") ||
669 parser.parseOperand(step))
670 return failure();
671
672 // Parse the optional initial iteration arguments.
674 regionArgs.push_back(inductionVariable);
675
676 // Parse optional type, else assume Index.
677 if (parser.parseOptionalColon())
678 type = builder.getIndexType();
679 else if (parser.parseType(type))
680 return failure();
681
682 // Resolve input operands.
683 regionArgs.front().type = type;
684 if (parser.resolveOperand(lb, type, result.operands) ||
685 parser.resolveOperand(ub, type, result.operands) ||
686 parser.resolveOperand(step, type, result.operands))
687 return failure();
688
689 // Parse the body region.
690 Region *body = result.addRegion();
691 if (parser.parseRegion(*body, regionArgs))
692 return failure();
693
694 ForOp::ensureTerminator(*body, builder, result.location);
695
696 // Parse the optional attribute list.
697 if (parser.parseOptionalAttrDict(result.attributes))
698 return failure();
699
700 return success();
701}
702
703void ForOp::print(OpAsmPrinter &p) {
704 p << " " << getInductionVar() << " = " << getLowerBound() << " to "
705 << getUpperBound() << " step " << getStep();
706
707 p << ' ';
708 if (Type t = getInductionVar().getType(); !t.isIndex())
709 p << " : " << t << ' ';
710 p.printRegion(getRegion(),
711 /*printEntryBlockArgs=*/false,
712 /*printBlockTerminators=*/false);
713 p.printOptionalAttrDict((*this)->getAttrs());
714}
715
716LogicalResult ForOp::verifyRegions() {
717 // Check that the body defines as single block argument for the induction
718 // variable.
719 if (getBody()->getNumArguments() != 1)
720 return emitOpError("expected body to have a single block argument for the "
721 "induction variable");
722
723 if (getInductionVar().getType() != getLowerBound().getType())
724 return emitOpError(
725 "expected induction variable to be same type as bounds and step");
726
727 return success();
728}
729
730//===----------------------------------------------------------------------===//
731// CallOp
732//===----------------------------------------------------------------------===//
733
734LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
735 // Check that the callee attribute was specified.
736 auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");
737 if (!fnAttr)
738 return emitOpError("requires a 'callee' symbol reference attribute");
739 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
740 if (!fn)
741 return emitOpError() << "'" << fnAttr.getValue()
742 << "' does not reference a valid function";
743
744 // Verify that the operand and result types match the callee.
745 auto fnType = fn.getFunctionType();
746 if (fnType.getNumInputs() != getNumOperands())
747 return emitOpError("incorrect number of operands for callee");
748
749 for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)
750 if (getOperand(i).getType() != fnType.getInput(i))
751 return emitOpError("operand type mismatch: expected operand type ")
752 << fnType.getInput(i) << ", but provided "
753 << getOperand(i).getType() << " for operand number " << i;
754
755 if (fnType.getNumResults() != getNumResults())
756 return emitOpError("incorrect number of results for callee");
757
758 for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)
759 if (getResult(i).getType() != fnType.getResult(i)) {
760 auto diag = emitOpError("result type mismatch at index ") << i;
761 diag.attachNote() << " op result types: " << getResultTypes();
762 diag.attachNote() << "function result types: " << fnType.getResults();
763 return diag;
764 }
765
766 return success();
767}
768
769FunctionType CallOp::getCalleeType() {
770 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
771}
772
773//===----------------------------------------------------------------------===//
774// DeclareFuncOp
775//===----------------------------------------------------------------------===//
776
777LogicalResult
778DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
779 // Check that the sym_name attribute was specified.
780 auto fnAttr = getSymNameAttr();
781 if (!fnAttr)
782 return emitOpError("requires a 'sym_name' symbol reference attribute");
783 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
784 if (!fn)
785 return emitOpError() << "'" << fnAttr.getValue()
786 << "' does not reference a valid function";
787
788 return success();
789}
790
791//===----------------------------------------------------------------------===//
792// FuncOp
793//===----------------------------------------------------------------------===//
794
795void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
796 FunctionType type, ArrayRef<NamedAttribute> attrs,
797 ArrayRef<DictionaryAttr> argAttrs) {
799 builder.getStringAttr(name));
800 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
801 state.attributes.append(attrs.begin(), attrs.end());
802 state.addRegion();
803
804 if (argAttrs.empty())
805 return;
806 assert(type.getNumInputs() == argAttrs.size());
808 builder, state, argAttrs, /*resultAttrs=*/{},
809 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
810}
811
812ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
813 auto buildFuncType =
814 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
816 std::string &) { return builder.getFunctionType(argTypes, results); };
817
819 parser, result, /*allowVariadic=*/false,
820 getFunctionTypeAttrName(result.name), buildFuncType,
821 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
822}
823
824void FuncOp::print(OpAsmPrinter &p) {
826 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
827 getArgAttrsAttrName(), getResAttrsAttrName());
828}
829
830LogicalResult FuncOp::verify() {
831 if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {
832 return emitOpError("cannot have lvalue type as argument");
833 }
834
835 if (getNumResults() > 1)
836 return emitOpError("requires zero or exactly one result, but has ")
837 << getNumResults();
838
839 if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
840 return emitOpError("cannot return array type");
841
842 return success();
843}
844
845//===----------------------------------------------------------------------===//
846// ReturnOp
847//===----------------------------------------------------------------------===//
848
849LogicalResult ReturnOp::verify() {
850 auto function = cast<FuncOp>((*this)->getParentOp());
851
852 // The operand number and types must match the function signature.
853 if (getNumOperands() != function.getNumResults())
854 return emitOpError("has ")
855 << getNumOperands() << " operands, but enclosing function (@"
856 << function.getName() << ") returns " << function.getNumResults();
857
858 if (function.getNumResults() == 1)
859 if (getOperand().getType() != function.getResultTypes()[0])
860 return emitError() << "type of the return operand ("
861 << getOperand().getType()
862 << ") doesn't match function result type ("
863 << function.getResultTypes()[0] << ")"
864 << " in function @" << function.getName();
865 return success();
866}
867
868//===----------------------------------------------------------------------===//
869// IfOp
870//===----------------------------------------------------------------------===//
871
872void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
873 bool addThenBlock, bool addElseBlock) {
874 assert((!addElseBlock || addThenBlock) &&
875 "must not create else block w/o then block");
876 result.addOperands(cond);
877
878 // Add regions and blocks.
879 OpBuilder::InsertionGuard guard(builder);
880 Region *thenRegion = result.addRegion();
881 if (addThenBlock)
882 builder.createBlock(thenRegion);
883 Region *elseRegion = result.addRegion();
884 if (addElseBlock)
885 builder.createBlock(elseRegion);
886}
887
888void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
889 bool withElseRegion) {
890 result.addOperands(cond);
891
892 // Build then region.
893 OpBuilder::InsertionGuard guard(builder);
894 Region *thenRegion = result.addRegion();
895 builder.createBlock(thenRegion);
896
897 // Build else region.
898 Region *elseRegion = result.addRegion();
899 if (withElseRegion) {
900 builder.createBlock(elseRegion);
901 }
902}
903
904void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
905 function_ref<void(OpBuilder &, Location)> thenBuilder,
906 function_ref<void(OpBuilder &, Location)> elseBuilder) {
907 assert(thenBuilder && "the builder callback for 'then' must be present");
908 result.addOperands(cond);
909
910 // Build then region.
911 OpBuilder::InsertionGuard guard(builder);
912 Region *thenRegion = result.addRegion();
913 builder.createBlock(thenRegion);
914 thenBuilder(builder, result.location);
915
916 // Build else region.
917 Region *elseRegion = result.addRegion();
918 if (elseBuilder) {
919 builder.createBlock(elseRegion);
920 elseBuilder(builder, result.location);
921 }
922}
923
924ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) {
925 // Create the regions for 'then'.
926 result.regions.reserve(2);
927 Region *thenRegion = result.addRegion();
928 Region *elseRegion = result.addRegion();
929
930 Builder &builder = parser.getBuilder();
932 Type i1Type = builder.getIntegerType(1);
933 if (parser.parseOperand(cond) ||
934 parser.resolveOperand(cond, i1Type, result.operands))
935 return failure();
936 // Parse the 'then' region.
937 if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))
938 return failure();
939 IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
940
941 // If we find an 'else' keyword then parse the 'else' region.
942 if (!parser.parseOptionalKeyword("else")) {
943 if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))
944 return failure();
945 IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);
946 }
947
948 // Parse the optional attribute list.
949 if (parser.parseOptionalAttrDict(result.attributes))
950 return failure();
951 return success();
952}
953
954void IfOp::print(OpAsmPrinter &p) {
955 bool printBlockTerminators = false;
956
957 p << " " << getCondition();
958 p << ' ';
959 p.printRegion(getThenRegion(),
960 /*printEntryBlockArgs=*/false,
961 /*printBlockTerminators=*/printBlockTerminators);
962
963 // Print the 'else' regions if it exists and has a block.
964 Region &elseRegion = getElseRegion();
965 if (!elseRegion.empty()) {
966 p << " else ";
967 p.printRegion(elseRegion,
968 /*printEntryBlockArgs=*/false,
969 /*printBlockTerminators=*/printBlockTerminators);
970 }
971
972 p.printOptionalAttrDict((*this)->getAttrs());
973}
974
975/// Given the region at `index`, or the parent operation if `index` is None,
976/// return the successor regions. These are the regions that may be selected
977/// during the flow of control. `operands` is a set of optional attributes
978/// that correspond to a constant value for each operand, or null if that
979/// operand is not a constant.
980void IfOp::getSuccessorRegions(RegionBranchPoint point,
982 // The `then` and the `else` region branch back to the parent operation.
983 if (!point.isParent()) {
984 regions.push_back(RegionSuccessor::parent());
985 return;
986 }
987
988 regions.push_back(RegionSuccessor(&getThenRegion()));
989
990 // Don't consider the else region if it is empty.
991 Region *elseRegion = &this->getElseRegion();
992 if (elseRegion->empty())
993 regions.push_back(RegionSuccessor::parent());
994 else
995 regions.push_back(RegionSuccessor(elseRegion));
996}
997
998ValueRange IfOp::getSuccessorInputs(RegionSuccessor successor) {
999 return successor.isParent() ? ValueRange(getOperation()->getResults())
1000 : ValueRange();
1001}
1002
1003void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,
1005 FoldAdaptor adaptor(operands, *this);
1006 auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
1007 if (!boolAttr || boolAttr.getValue())
1008 regions.emplace_back(&getThenRegion());
1009
1010 // If the else region is empty, execution continues after the parent op.
1011 if (!boolAttr || !boolAttr.getValue()) {
1012 if (!getElseRegion().empty())
1013 regions.emplace_back(&getElseRegion());
1014 else
1015 regions.emplace_back(RegionSuccessor::parent());
1016 }
1017}
1018
1019void IfOp::getRegionInvocationBounds(
1020 ArrayRef<Attribute> operands,
1021 SmallVectorImpl<InvocationBounds> &invocationBounds) {
1022 if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
1023 // If the condition is known, then one region is known to be executed once
1024 // and the other zero times.
1025 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
1026 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
1027 } else {
1028 // Non-constant condition. Each region may be executed 0 or 1 times.
1029 invocationBounds.assign(2, {0, 1});
1030 }
1031}
1032
1033//===----------------------------------------------------------------------===//
1034// IncludeOp
1035//===----------------------------------------------------------------------===//
1036
1037void IncludeOp::print(OpAsmPrinter &p) {
1038 bool standardInclude = getIsStandardInclude();
1039
1040 p << " ";
1041 if (standardInclude)
1042 p << "<";
1043 p << "\"" << getInclude() << "\"";
1044 if (standardInclude)
1045 p << ">";
1046}
1047
1048ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {
1049 bool standardInclude = !parser.parseOptionalLess();
1050
1051 StringAttr include;
1052 OptionalParseResult includeParseResult =
1053 parser.parseOptionalAttribute(include, "include", result.attributes);
1054 if (!includeParseResult.has_value())
1055 return parser.emitError(parser.getNameLoc()) << "expected string attribute";
1056
1057 if (standardInclude && parser.parseOptionalGreater())
1058 return parser.emitError(parser.getNameLoc())
1059 << "expected trailing '>' for standard include";
1060
1061 if (standardInclude)
1062 result.addAttribute("is_standard_include",
1063 UnitAttr::get(parser.getContext()));
1064
1065 return success();
1066}
1067
1068//===----------------------------------------------------------------------===//
1069// LiteralOp
1070//===----------------------------------------------------------------------===//
1071
1072/// The literal op requires a non-empty value.
1073LogicalResult emitc::LiteralOp::verify() {
1074 if (getValue().empty())
1075 return emitOpError() << "value must not be empty";
1076 return success();
1077}
1078//===----------------------------------------------------------------------===//
1079// SubOp
1080//===----------------------------------------------------------------------===//
1081
1082LogicalResult SubOp::verify() {
1083 Type lhsType = getLhs().getType();
1084 Type rhsType = getRhs().getType();
1085 Type resultType = getResult().getType();
1086
1087 if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
1088 return emitOpError("rhs can only be a pointer if lhs is a pointer");
1089
1090 if (isa<emitc::PointerType>(lhsType) &&
1091 !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
1092 return emitOpError("requires that rhs is an integer, pointer or of opaque "
1093 "type if lhs is a pointer");
1094
1095 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
1096 !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))
1097 return emitOpError("requires that the result is an integer, ptrdiff_t or "
1098 "of opaque type if lhs and rhs are pointers");
1099 return success();
1100}
1101
1102//===----------------------------------------------------------------------===//
1103// VariableOp
1104//===----------------------------------------------------------------------===//
1105
1106LogicalResult emitc::VariableOp::verify() {
1107 return verifyInitializationAttribute(getOperation(), getValueAttr());
1108}
1109
1110//===----------------------------------------------------------------------===//
1111// YieldOp
1112//===----------------------------------------------------------------------===//
1113
1114LogicalResult emitc::YieldOp::verify() {
1115 Value result = getResult();
1116 Operation *containingOp = getOperation()->getParentOp();
1117
1118 if (!isa<DoOp>(containingOp) && result && containingOp->getNumResults() != 1)
1119 return emitOpError() << "yields a value not returned by parent";
1120
1121 if (!isa<DoOp>(containingOp) && !result && containingOp->getNumResults() != 0)
1122 return emitOpError() << "does not yield a value to be returned by parent";
1123
1124 if (result && isa<emitc::LValueType>(result.getType()) &&
1125 !isa<ExpressionOp>(containingOp))
1126 return emitOpError() << "yielding lvalues is not supported for this op";
1127
1128 return success();
1129}
1130
1131//===----------------------------------------------------------------------===//
1132// SubscriptOp
1133//===----------------------------------------------------------------------===//
1134
1135LogicalResult emitc::SubscriptOp::verify() {
1136 // Checks for array operand.
1137 if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {
1138 // Check number of indices.
1139 if (getIndices().size() != (size_t)arrayType.getRank()) {
1140 return emitOpError() << "on array operand requires number of indices ("
1141 << getIndices().size()
1142 << ") to match the rank of the array type ("
1143 << arrayType.getRank() << ")";
1144 }
1145 // Check types of index operands.
1146 for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {
1147 Type type = getIndices()[i].getType();
1148 if (!isIntegerIndexOrOpaqueType(type)) {
1149 return emitOpError() << "on array operand requires index operand " << i
1150 << " to be integer-like, but got " << type;
1151 }
1152 }
1153 // Check element type.
1154 Type elementType = arrayType.getElementType();
1155 Type resultType = getType().getValueType();
1156 if (elementType != resultType) {
1157 return emitOpError() << "on array operand requires element type ("
1158 << elementType << ") and result type (" << resultType
1159 << ") to match";
1160 }
1161 return success();
1162 }
1163
1164 // Checks for pointer operand.
1165 if (auto pointerType =
1166 llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {
1167 // Check number of indices.
1168 if (getIndices().size() != 1) {
1169 return emitOpError()
1170 << "on pointer operand requires one index operand, but got "
1171 << getIndices().size();
1172 }
1173 // Check types of index operand.
1174 Type type = getIndices()[0].getType();
1175 if (!isIntegerIndexOrOpaqueType(type)) {
1176 return emitOpError() << "on pointer operand requires index operand to be "
1177 "integer-like, but got "
1178 << type;
1179 }
1180 // Check pointee type.
1181 Type pointeeType = pointerType.getPointee();
1182 Type resultType = getType().getValueType();
1183 if (pointeeType != resultType) {
1184 return emitOpError() << "on pointer operand requires pointee type ("
1185 << pointeeType << ") and result type (" << resultType
1186 << ") to match";
1187 }
1188 return success();
1189 }
1190
1191 // The operand has opaque type, so we can't assume anything about the number
1192 // or types of index operands.
1193 return success();
1194}
1195
1196//===----------------------------------------------------------------------===//
1197// VerbatimOp
1198//===----------------------------------------------------------------------===//
1199
1200LogicalResult emitc::VerbatimOp::verify() {
1201 auto errorCallback = [&]() -> InFlightDiagnostic {
1202 return this->emitOpError();
1203 };
1204 FailureOr<SmallVector<ReplacementItem>> fmt =
1205 ::parseFormatString(getValue(), getFmtArgs(), errorCallback);
1206 if (failed(fmt))
1207 return failure();
1208
1209 size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) {
1210 return std::holds_alternative<Placeholder>(item);
1211 });
1212
1213 if (numPlaceholders != getFmtArgs().size()) {
1214 return emitOpError()
1215 << "requires operands for each placeholder in the format string";
1216 }
1217 return success();
1218}
1219
1220FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {
1221 // Error checking is done in verify.
1222 return ::parseFormatString(getValue(), getFmtArgs());
1223}
1224
1225//===----------------------------------------------------------------------===//
1226// EmitC Enums
1227//===----------------------------------------------------------------------===//
1228
1229#include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
1230
1231//===----------------------------------------------------------------------===//
1232// EmitC Attributes
1233//===----------------------------------------------------------------------===//
1234
1235#define GET_ATTRDEF_CLASSES
1236#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
1237
1238//===----------------------------------------------------------------------===//
1239// EmitC Types
1240//===----------------------------------------------------------------------===//
1241
1242#define GET_TYPEDEF_CLASSES
1243#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
1244
1245//===----------------------------------------------------------------------===//
1246// ArrayType
1247//===----------------------------------------------------------------------===//
1248
1249Type emitc::ArrayType::parse(AsmParser &parser) {
1250 if (parser.parseLess())
1251 return Type();
1252
1253 SmallVector<int64_t, 4> dimensions;
1254 if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,
1255 /*withTrailingX=*/true))
1256 return Type();
1257 // Parse the element type.
1258 auto typeLoc = parser.getCurrentLocation();
1259 Type elementType;
1260 if (parser.parseType(elementType))
1261 return Type();
1262
1263 // Check that array is formed from allowed types.
1264 if (!isValidElementType(elementType))
1265 return parser.emitError(typeLoc, "invalid array element type '")
1266 << elementType << "'",
1267 Type();
1268 if (parser.parseGreater())
1269 return Type();
1270 return parser.getChecked<ArrayType>(dimensions, elementType);
1271}
1272
1273void emitc::ArrayType::print(AsmPrinter &printer) const {
1274 printer << "<";
1275 for (int64_t dim : getShape()) {
1276 printer << dim << 'x';
1277 }
1278 printer.printType(getElementType());
1279 printer << ">";
1280}
1281
1282LogicalResult emitc::ArrayType::verify(
1284 ::llvm::ArrayRef<int64_t> shape, Type elementType) {
1285 if (shape.empty())
1286 return emitError() << "shape must not be empty";
1287
1288 for (int64_t dim : shape) {
1289 if (dim < 0)
1290 return emitError() << "dimensions must have non-negative size";
1291 }
1292
1293 if (!elementType)
1294 return emitError() << "element type must not be none";
1295
1296 if (!isValidElementType(elementType))
1297 return emitError() << "invalid array element type";
1298
1299 return success();
1300}
1301
1302emitc::ArrayType
1303emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
1304 Type elementType) const {
1305 if (!shape)
1306 return emitc::ArrayType::get(getShape(), elementType);
1307 return emitc::ArrayType::get(*shape, elementType);
1308}
1309
1310//===----------------------------------------------------------------------===//
1311// LValueType
1312//===----------------------------------------------------------------------===//
1313
1314LogicalResult mlir::emitc::LValueType::verify(
1316 mlir::Type value) {
1317 // Check that the wrapped type is valid. This especially forbids nested
1318 // lvalue types.
1319 if (!isSupportedEmitCType(value))
1320 return emitError()
1321 << "!emitc.lvalue must wrap supported emitc type, but got " << value;
1322
1323 if (llvm::isa<emitc::ArrayType>(value))
1324 return emitError() << "!emitc.lvalue cannot wrap !emitc.array type";
1325
1326 return success();
1327}
1328
1329//===----------------------------------------------------------------------===//
1330// OpaqueType
1331//===----------------------------------------------------------------------===//
1332
1333LogicalResult mlir::emitc::OpaqueType::verify(
1335 llvm::StringRef value) {
1336 if (value.empty()) {
1337 return emitError() << "expected non empty string in !emitc.opaque type";
1338 }
1339 if (value.back() == '*') {
1340 return emitError() << "pointer not allowed as outer type with "
1341 "!emitc.opaque, use !emitc.ptr instead";
1342 }
1343 return success();
1344}
1345
1346//===----------------------------------------------------------------------===//
1347// PointerType
1348//===----------------------------------------------------------------------===//
1349
1350LogicalResult mlir::emitc::PointerType::verify(
1352 if (llvm::isa<emitc::LValueType>(value))
1353 return emitError() << "pointers to lvalues are not allowed";
1354
1355 return success();
1356}
1357
1358//===----------------------------------------------------------------------===//
1359// GlobalOp
1360//===----------------------------------------------------------------------===//
1362 TypeAttr type,
1363 Attribute initialValue) {
1364 p << type;
1365 if (initialValue) {
1366 p << " = ";
1367 p.printAttributeWithoutType(initialValue);
1368 }
1369}
1370
1372 if (auto array = llvm::dyn_cast<ArrayType>(type))
1373 return RankedTensorType::get(array.getShape(), array.getElementType());
1374 return type;
1375}
1376
1377static ParseResult
1379 Attribute &initialValue) {
1380 Type type;
1381 if (parser.parseType(type))
1382 return failure();
1383
1384 typeAttr = TypeAttr::get(type);
1385
1386 if (parser.parseOptionalEqual())
1387 return success();
1388
1389 if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))
1390 return failure();
1391
1392 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1393 initialValue))
1394 return parser.emitError(parser.getNameLoc())
1395 << "initial value should be a integer, float, elements or opaque "
1396 "attribute";
1397 return success();
1398}
1399
1400LogicalResult GlobalOp::verify() {
1401 if (!isSupportedEmitCType(getType())) {
1402 return emitOpError("expected valid emitc type");
1403 }
1404 if (getInitialValue().has_value()) {
1405 Attribute initValue = getInitialValue().value();
1406 // Check that the type of the initial value is compatible with the type of
1407 // the global variable.
1408 if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1409 auto arrayType = llvm::dyn_cast<ArrayType>(getType());
1410 if (!arrayType)
1411 return emitOpError("expected array type, but got ") << getType();
1412
1413 Type initType = elementsAttr.getType();
1415 if (initType != tensorType) {
1416 return emitOpError("initial value expected to be of type ")
1417 << getType() << ", but was of type " << initType;
1418 }
1419 } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1420 if (intAttr.getType() != getType()) {
1421 return emitOpError("initial value expected to be of type ")
1422 << getType() << ", but was of type " << intAttr.getType();
1423 }
1424 } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1425 if (floatAttr.getType() != getType()) {
1426 return emitOpError("initial value expected to be of type ")
1427 << getType() << ", but was of type " << floatAttr.getType();
1428 }
1429 } else if (!isa<emitc::OpaqueAttr>(initValue)) {
1430 return emitOpError("initial value should be a integer, float, elements "
1431 "or opaque attribute, but got ")
1432 << initValue;
1433 }
1434 }
1435 if (getStaticSpecifier() && getExternSpecifier()) {
1436 return emitOpError("cannot have both static and extern specifiers");
1437 }
1438 return success();
1439}
1440
1441//===----------------------------------------------------------------------===//
1442// GetGlobalOp
1443//===----------------------------------------------------------------------===//
1444
1445LogicalResult
1446GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1447 // Verify that the type matches the type of the global variable.
1448 auto global =
1449 symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1450 if (!global)
1451 return emitOpError("'")
1452 << getName() << "' does not reference a valid emitc.global";
1453
1454 Type resultType = getResult().getType();
1455 Type globalType = global.getType();
1456
1457 // global has array type
1458 if (llvm::isa<ArrayType>(globalType)) {
1459 if (globalType != resultType)
1460 return emitOpError("on array type expects result type ")
1461 << resultType << " to match type " << globalType
1462 << " of the global @" << getName();
1463 return success();
1464 }
1465
1466 // global has non-array type
1467 auto lvalueType = dyn_cast<LValueType>(resultType);
1468 if (!lvalueType)
1469 return emitOpError("on non-array type expects result type to be an "
1470 "lvalue type for the global @")
1471 << getName();
1472 if (lvalueType.getValueType() != globalType)
1473 return emitOpError("on non-array type expects result inner type ")
1474 << lvalueType.getValueType() << " to match type " << globalType
1475 << " of the global @" << getName();
1476 return success();
1477}
1478
1479//===----------------------------------------------------------------------===//
1480// SwitchOp
1481//===----------------------------------------------------------------------===//
1482
1483/// Parse the case regions and values.
1484static ParseResult
1486 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
1487 SmallVector<int64_t> caseValues;
1488 while (succeeded(parser.parseOptionalKeyword("case"))) {
1489 int64_t value;
1490 Region &region = *caseRegions.emplace_back(std::make_unique<Region>());
1491 if (parser.parseInteger(value) ||
1492 parser.parseRegion(region, /*arguments=*/{}))
1493 return failure();
1494 caseValues.push_back(value);
1495 }
1496 cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);
1497 return success();
1498}
1499
1500/// Print the case regions and values.
1502 DenseI64ArrayAttr cases, RegionRange caseRegions) {
1503 for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {
1504 p.printNewline();
1505 p << "case " << value << ' ';
1506 p.printRegion(*region, /*printEntryBlockArgs=*/false);
1507 }
1508}
1509
1510static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region,
1511 const Twine &name) {
1512 auto yield = dyn_cast<emitc::YieldOp>(region.front().back());
1513 if (!yield)
1514 return op.emitOpError("expected region to end with emitc.yield, but got ")
1515 << region.front().back().getName();
1516
1517 if (yield.getNumOperands() != 0) {
1518 return (op.emitOpError("expected each region to return ")
1519 << "0 values, but " << name << " returns "
1520 << yield.getNumOperands())
1521 .attachNote(yield.getLoc())
1522 << "see yield operation here";
1523 }
1524
1525 return success();
1526}
1527
1528LogicalResult emitc::SwitchOp::verify() {
1529 if (!isIntegerIndexOrOpaqueType(getArg().getType()))
1530 return emitOpError("unsupported type ") << getArg().getType();
1531
1532 if (getCases().size() != getCaseRegions().size()) {
1533 return emitOpError("has ")
1534 << getCaseRegions().size() << " case regions but "
1535 << getCases().size() << " case values";
1536 }
1537
1538 DenseSet<int64_t> valueSet;
1539 for (int64_t value : getCases())
1540 if (!valueSet.insert(value).second)
1541 return emitOpError("has duplicate case value: ") << value;
1542
1543 if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))
1544 return failure();
1545
1546 for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
1547 if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))
1548 return failure();
1549
1550 return success();
1551}
1552
1553unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }
1554
1555Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }
1556
1557Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {
1558 assert(idx < getNumCases() && "case index out-of-bounds");
1559 return getCaseRegions()[idx].front();
1560}
1561
1562void SwitchOp::getSuccessorRegions(
1564 llvm::append_range(successors, getRegions());
1565}
1566
1567/// Returns the int64_t value of an IntegerAttr regardless of whether its type
1568/// is signless, signed, or unsigned. Returns std::nullopt for unknown types.
1569static std::optional<int64_t> getIntAttrValue(IntegerAttr attr) {
1570 Type type = attr.getType();
1571 if (type.isIndex() || type.isSignlessInteger())
1572 return attr.getInt();
1573 if (type.isSignedInteger())
1574 return attr.getSInt();
1575 if (type.isUnsignedInteger())
1576 return static_cast<int64_t>(attr.getUInt());
1577 return std::nullopt;
1578}
1579
1580void SwitchOp::getEntrySuccessorRegions(
1581 ArrayRef<Attribute> operands,
1583 FoldAdaptor adaptor(operands, *this);
1584
1585 // If a constant was not provided, all regions are possible successors.
1586 auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
1587 if (!arg) {
1588 llvm::append_range(successors, getRegions());
1589 return;
1590 }
1591
1592 std::optional<int64_t> argValue = getIntAttrValue(arg);
1593 if (!argValue) {
1594 // Unknown type; conservatively treat all regions as possible.
1595 llvm::append_range(successors, getRegions());
1596 return;
1597 }
1598
1599 // Otherwise, try to find a case with a matching value. If not, the
1600 // default region is the only successor.
1601 for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
1602 if (caseValue == *argValue) {
1603 successors.emplace_back(&caseRegion);
1604 return;
1605 }
1606 }
1607 successors.emplace_back(&getDefaultRegion());
1608}
1609
1610void SwitchOp::getRegionInvocationBounds(
1612 auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
1613 if (!operandValue) {
1614 // All regions are invoked at most once.
1615 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1616 return;
1617 }
1618
1619 std::optional<int64_t> maybeIntValue = getIntAttrValue(operandValue);
1620 if (!maybeIntValue) {
1621 // Unknown type; conservatively treat all regions as possible.
1622 bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
1623 return;
1624 }
1625
1626 unsigned liveIndex = getNumRegions() - 1;
1627 const auto *iteratorToInt = llvm::find(getCases(), *maybeIntValue);
1628
1629 liveIndex = iteratorToInt != getCases().end()
1630 ? std::distance(getCases().begin(), iteratorToInt)
1631 : liveIndex;
1632
1633 for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
1634 ++regIndex)
1635 bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
1636}
1637
1638//===----------------------------------------------------------------------===//
1639// FileOp
1640//===----------------------------------------------------------------------===//
1641void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {
1642 state.addRegion()->emplaceBlock();
1643 state.attributes.push_back(
1644 builder.getNamedAttr("id", builder.getStringAttr(id)));
1645}
1646
1647//===----------------------------------------------------------------------===//
1648// FieldOp
1649//===----------------------------------------------------------------------===//
1650
1652 TypeAttr type,
1653 Attribute initialValue) {
1654 p << type;
1655 if (initialValue) {
1656 p << " = ";
1657 p.printAttributeWithoutType(initialValue);
1658 }
1659}
1660
1662 if (auto array = llvm::dyn_cast<ArrayType>(type))
1663 return RankedTensorType::get(array.getShape(), array.getElementType());
1664 return type;
1665}
1666
1667static ParseResult
1669 Attribute &initialValue) {
1670 Type type;
1671 if (parser.parseType(type))
1672 return failure();
1673
1674 typeAttr = TypeAttr::get(type);
1675
1676 if (parser.parseOptionalEqual())
1677 return success();
1678
1679 if (parser.parseAttribute(initialValue, getInitializerTypeForField(type)))
1680 return failure();
1681
1682 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1683 initialValue))
1684 return parser.emitError(parser.getNameLoc())
1685 << "initial value should be a integer, float, elements or opaque "
1686 "attribute";
1687 return success();
1688}
1689
1690LogicalResult FieldOp::verify() {
1692 return emitOpError("expected valid emitc type");
1693
1694 Operation *parentOp = getOperation()->getParentOp();
1695 if (!parentOp || !isa<emitc::ClassOp>(parentOp))
1696 return emitOpError("field must be nested within an emitc.class operation");
1697
1698 StringAttr symName = getSymNameAttr();
1699 if (!symName || symName.getValue().empty())
1700 return emitOpError("field must have a non-empty symbol name");
1701
1702 return success();
1703}
1704
1705//===----------------------------------------------------------------------===//
1706// GetFieldOp
1707//===----------------------------------------------------------------------===//
1708
1709LogicalResult GetFieldOp::verify() {
1710 auto parentClassOp = getOperation()->getParentOfType<emitc::ClassOp>();
1711 if (!parentClassOp.getOperation())
1712 return emitOpError(" must be nested within an emitc.class operation");
1713
1714 return success();
1715}
1716
1717LogicalResult GetFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1718 mlir::FlatSymbolRefAttr fieldNameAttr = getFieldNameAttr();
1719 FieldOp fieldOp =
1720 symbolTable.lookupNearestSymbolFrom<FieldOp>(*this, fieldNameAttr);
1721 if (!fieldOp)
1722 return emitOpError("field '")
1723 << fieldNameAttr << "' not found in the class";
1724
1725 Type getFieldResultType = getResult().getType();
1726 Type fieldType = fieldOp.getType();
1727
1728 if (fieldType != getFieldResultType)
1729 return emitOpError("result type ")
1730 << getFieldResultType << " does not match field '" << fieldNameAttr
1731 << "' type " << fieldType;
1732
1733 return success();
1734}
1735
1736//===----------------------------------------------------------------------===//
1737// DoOp
1738//===----------------------------------------------------------------------===//
1739
1740void DoOp::print(OpAsmPrinter &p) {
1741 p << ' ';
1742 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
1743 p << " while ";
1744 p.printRegion(getConditionRegion());
1745 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs());
1746}
1747
1748LogicalResult emitc::DoOp::verify() {
1749 Block &condBlock = getConditionRegion().front();
1750
1751 if (condBlock.getOperations().size() != 2)
1752 return emitOpError(
1753 "condition region must contain exactly two operations: "
1754 "'emitc.expression' followed by 'emitc.yield', but found ")
1755 << condBlock.getOperations().size() << " operations";
1756
1757 Operation &first = condBlock.front();
1758 auto exprOp = dyn_cast<emitc::ExpressionOp>(first);
1759 if (!exprOp)
1760 return emitOpError("expected first op in condition region to be "
1761 "'emitc.expression', but got ")
1762 << first.getName();
1763
1764 if (!exprOp.getResult().getType().isInteger(1))
1765 return emitOpError("emitc.expression in condition region must return "
1766 "'i1', but returns ")
1767 << exprOp.getResult().getType();
1768
1769 Operation &last = condBlock.back();
1770 auto condYield = dyn_cast<emitc::YieldOp>(last);
1771 if (!condYield)
1772 return emitOpError("expected last op in condition region to be "
1773 "'emitc.yield', but got ")
1774 << last.getName();
1775
1776 if (condYield.getNumOperands() != 1)
1777 return emitOpError("expected condition region to return 1 value, but "
1778 "it returns ")
1779 << condYield.getNumOperands() << " values";
1780
1781 if (condYield.getOperand(0) != exprOp.getResult())
1782 return emitError("'emitc.yield' must return result of "
1783 "'emitc.expression' from this condition region");
1784
1785 Block &bodyBlock = getBodyRegion().front();
1786 if (bodyBlock.mightHaveTerminator())
1787 return emitOpError("body region must not contain terminator");
1788
1789 return success();
1790}
1791
1792ParseResult DoOp::parse(OpAsmParser &parser, OperationState &result) {
1793 Region *bodyRegion = result.addRegion();
1794 Region *condRegion = result.addRegion();
1795
1796 if (parser.parseRegion(*bodyRegion) || parser.parseKeyword("while") ||
1797 parser.parseRegion(*condRegion))
1798 return failure();
1799
1800 if (bodyRegion->empty())
1801 bodyRegion->emplaceBlock();
1802
1803 return parser.parseOptionalAttrDictWithKeyword(result.attributes);
1804}
1805
1806//===----------------------------------------------------------------------===//
1807// TableGen'd op method definitions
1808//===----------------------------------------------------------------------===//
1809
1810#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"
1811
1812#define GET_OP_CLASSES
1813#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:1569
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:1510
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1378
static Type getInitializerTypeForField(Type type)
Definition EmitC.cpp:1661
static ParseResult parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
Definition EmitC.cpp:1668
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:1361
static ParseResult parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, SmallVectorImpl< std::unique_ptr< Region > > &caseRegions)
Parse the case regions and values.
Definition EmitC.cpp:1485
static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op, TypeAttr type, Attribute initialValue)
Definition EmitC.cpp:1651
static void printSwitchCases(OpAsmPrinter &p, Operation *op, DenseI64ArrayAttr cases, RegionRange caseRegions)
Print the case regions and values.
Definition EmitC.cpp:1501
static Type getInitializerTypeForGlobal(Type type)
Definition EmitC.cpp:1371
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:433
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:252
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:116
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:404
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:430
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: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.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
Definition OpenACC.cpp:5143
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.