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