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