18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/Support/Casting.h"
25#include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc"
31void EmitCDialect::initialize() {
34#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
37#define GET_TYPEDEF_LIST
38#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
41#define GET_ATTRDEF_LIST
42#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
51 return emitc::ConstantOp::create(builder, loc, type, value);
57 emitc::YieldOp::create(builder, loc);
61 if (llvm::isa<emitc::OpaqueType>(type))
63 if (
auto ptrType = llvm::dyn_cast<emitc::PointerType>(type))
65 if (
auto arrayType = llvm::dyn_cast<emitc::ArrayType>(type)) {
66 auto elemType = arrayType.getElementType();
67 return !llvm::isa<emitc::ArrayType>(elemType) &&
72 if (llvm::isa<IntegerType>(type))
74 if (llvm::isa<FloatType>(type))
76 if (
auto tensorType = llvm::dyn_cast<TensorType>(type)) {
77 if (!tensorType.hasStaticShape()) {
80 auto elemType = tensorType.getElementType();
81 if (llvm::isa<emitc::ArrayType>(elemType)) {
86 if (
auto tupleType = llvm::dyn_cast<TupleType>(type)) {
87 return llvm::all_of(tupleType.getTypes(), [](
Type type) {
88 return !llvm::isa<emitc::ArrayType>(type) && isSupportedEmitCType(type);
95 if (
auto intType = llvm::dyn_cast<IntegerType>(type)) {
96 switch (intType.getWidth()) {
111 return llvm::isa<IndexType, emitc::OpaqueType>(type) ||
116 if (
auto floatType = llvm::dyn_cast<FloatType>(type)) {
117 switch (floatType.getWidth()) {
119 return llvm::isa<Float16Type, BFloat16Type>(type);
131 return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>(
138 isa<emitc::PointerType>(type);
145 assert(op->
getNumResults() == 1 &&
"operation must have 1 result");
147 if (llvm::isa<emitc::OpaqueAttr>(value))
150 if (llvm::isa<StringAttr>(value))
152 <<
"string attributes are not supported, use #emitc.opaque instead";
155 if (
auto lType = dyn_cast<LValueType>(resultType))
156 resultType = lType.getValueType();
157 Type attrType = cast<TypedAttr>(value).getType();
162 if (resultType != attrType)
164 <<
"requires attribute to either be an #emitc.opaque attribute or "
166 << attrType <<
") to match the op's result type (" << resultType
177template <
class ArgType>
179 StringRef toParse, ArgType fmtArgs,
184 if (fmtArgs.empty()) {
185 items.push_back(toParse);
189 while (!toParse.empty()) {
190 size_t idx = toParse.find(
'{');
191 if (idx == StringRef::npos) {
193 items.push_back(toParse);
198 items.push_back(toParse.take_front(idx));
199 toParse = toParse.drop_front(idx);
202 if (toParse.size() < 2) {
203 return emitError() <<
"expected '}' after unescaped '{' at end of string";
206 char nextChar = toParse[1];
207 if (nextChar ==
'{') {
209 items.push_back(toParse.take_front(1));
210 toParse = toParse.drop_front(2);
213 if (nextChar ==
'}') {
215 toParse = toParse.drop_front(2);
220 return emitError() <<
"expected '}' after unescaped '{'";
231LogicalResult AddressOfOp::verify() {
232 emitc::LValueType referenceType = getReference().getType();
233 emitc::PointerType resultType = getResult().getType();
235 if (referenceType.getValueType() != resultType.getPointee())
236 return emitOpError(
"requires result to be a pointer to the type "
237 "referenced by operand");
246LogicalResult AddOp::verify() {
247 Type lhsType = getLhs().getType();
248 Type rhsType = getRhs().getType();
250 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType))
251 return emitOpError(
"requires that at most one operand is a pointer");
253 if ((isa<emitc::PointerType>(lhsType) &&
254 !isa<IntegerType, emitc::OpaqueType>(rhsType)) ||
255 (isa<emitc::PointerType>(rhsType) &&
256 !isa<IntegerType, emitc::OpaqueType>(lhsType)))
257 return emitOpError(
"requires that one operand is an integer or of opaque "
258 "type if the other is a pointer");
267template <
typename AssignmentOp>
271 if (!variable.getDefiningOp())
272 return op.emitOpError() <<
"cannot assign to block argument";
274 Type valueType = op.getValue().getType();
275 Type variableType = variable.getType().getValueType();
276 if (variableType != valueType)
277 return op.emitOpError() <<
"requires value's type (" << valueType
278 <<
") to match variable's type (" << variableType
279 <<
")\n variable: " << variable
280 <<
"\n value: " << op.getValue() <<
"\n";
301 Type input = inputs.front(), output = outputs.front();
303 if (
auto arrayType = dyn_cast<emitc::ArrayType>(input)) {
304 if (
auto pointerType = dyn_cast<emitc::PointerType>(output)) {
305 return (arrayType.getElementType() == pointerType.getPointee()) &&
306 arrayType.getShape().size() == 1 && arrayType.getShape()[0] >= 1;
322void emitc::CastOp::getEffects(
337 std::optional<ArrayAttr> args,
338 std::optional<ArrayAttr> templateArgs,
339 TypeRange resultTypes,
size_t numArgsOperands) {
342 return op->
emitOpError(
"callee must not be empty");
346 auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
347 if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {
352 return op->
emitOpError(
"index argument is out of range");
354 }
else if (llvm::isa<ArrayAttr>(arg)) {
355 return op->
emitOpError(
"array argument has no type");
362 if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
363 return op->
emitOpError(
"template argument has invalid type");
367 if (llvm::any_of(resultTypes, llvm::IsaPred<ArrayType>)) {
368 return op->
emitOpError() <<
"cannot return array type";
374LogicalResult emitc::CallOpaqueOp::verify() {
376 getTemplateArgs(), getResultTypes(),
380LogicalResult emitc::MemberCallOpaqueOp::verify() {
382 getTemplateArgs(), getResultTypes(),
383 getArgOperands().size());
390LogicalResult emitc::ConstantOp::verify() {
394 if (
auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) {
395 if (opaqueValue.getValue().empty())
396 return emitOpError() <<
"value must not be empty";
401OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) {
return getValue(); }
407LogicalResult DereferenceOp::verify() {
411 return emitOpError(
"requires result to be an lvalue of the type "
412 "pointed to by operand");
423struct RemoveRecurringExpressionOperands
425 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
426 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
427 PatternRewriter &rewriter)
const override {
432 for (
auto [i, operand] : llvm::enumerate(expressionOp.getDefs())) {
433 if (uniqueOperands.contains(operand))
435 uniqueOperands.insert(operand);
436 firstIndexOf[operand] = i;
440 if (uniqueOperands.size() == expressionOp.getDefs().size())
445 auto uniqueExpression = emitc::ExpressionOp::create(
446 rewriter, expressionOp.getLoc(), expressionOp.getResult().getType(),
447 uniqueOperands.getArrayRef(), expressionOp.getDoNotInline());
448 Block &uniqueExpressionBody = uniqueExpression.createBody();
453 Block *expressionBody = expressionOp.getBody();
454 for (
auto [operand, arg] :
455 llvm::zip(expressionOp.getOperands(), expressionBody->
getArguments()))
456 mapper.
map(arg, uniqueExpressionBody.
getArgument(firstIndexOf[operand]));
459 for (Operation &opToClone : *expressionOp.getBody())
460 rewriter.
clone(opToClone, mapper);
463 rewriter.
replaceOp(expressionOp, uniqueExpression);
474 using OpRewritePattern<ExpressionOp>::OpRewritePattern;
475 LogicalResult matchAndRewrite(ExpressionOp expressionOp,
476 PatternRewriter &rewriter)
const override {
477 auto yieldOp = cast<YieldOp>(expressionOp.getBody()->getTerminator());
478 Value yieldedValue = yieldOp.getResult();
479 auto blockArg = dyn_cast_if_present<BlockArgument>(yieldedValue);
483 expressionOp.getOperand(blockArg.getArgNumber()));
492 results.
add<RemoveRecurringExpressionOperands, FoldTrivialExpressionOp>(
501 result.addAttribute(ExpressionOp::getDoNotInlineAttrName(
result.name),
506 "expected function type");
507 auto fnType = llvm::dyn_cast<FunctionType>(type);
510 "expected function type");
514 if (fnType.getNumResults() != 1)
516 "expected single return type");
517 result.addTypes(fnType.getResults());
521 bool enableNameShadowing = uniqueOperands.size() ==
result.operands.size();
523 if (enableNameShadowing) {
524 for (
auto [unresolvedOperand, operandType] :
525 llvm::zip(operands, fnType.getInputs())) {
527 argInfo.
ssaName = unresolvedOperand;
528 argInfo.
type = operandType;
529 argsInfo.push_back(argInfo);
533 if (parser.
parseRegion(*body, argsInfo, enableNameShadowing))
535 if (!enableNameShadowing) {
538 beforeRegionLoc,
"with recurring operands expected block arguments");
546 auto operands = getDefs();
551 bool printEntryBlockArgs =
true;
552 if (uniqueOperands.size() == operands.size()) {
554 printEntryBlockArgs =
false;
561 auto yieldOp = cast<YieldOp>(getBody()->getTerminator());
562 Value yieldedValue = yieldOp.getResult();
566LogicalResult ExpressionOp::verify() {
567 Type resultType = getResult().getType();
568 Region ®ion = getRegion();
573 return emitOpError(
"must yield a value at termination");
576 Value yieldResult = yield.getResult();
579 return emitOpError(
"must yield a value at termination");
584 return emitOpError(
"yielded value has no defining op");
587 return emitOpError(
"yielded value not defined within expression");
591 if (resultType != yieldType)
592 return emitOpError(
"requires yielded type to match return type");
595 auto expressionInterface = dyn_cast<emitc::CExpressionInterface>(op);
596 if (!expressionInterface)
597 return emitOpError(
"contains an unsupported operation");
598 if (op.getNumResults() != 1)
599 return emitOpError(
"requires exactly one result for each operation");
602 return emitOpError(
"contains an unused operation");
609 worklist.push_back(rootOp);
610 while (!worklist.empty()) {
613 if (visited.contains(op)) {
614 auto cExpr = cast<CExpressionInterface>(op);
615 if (!cExpr.alwaysInline() && cExpr.hasSideEffects())
617 "requires exactly one use for operations with side effects");
621 if (
Operation *def = operand.getDefiningOp()) {
622 worklist.push_back(def);
628 if (getDoNotInline() &&
629 cast<emitc::CExpressionInterface>(rootOp).alwaysInline()) {
630 return emitOpError(
"root operation must be inlined but expression is marked"
652 ForOp::ensureTerminator(*bodyRegion, builder,
result.location);
679 regionArgs.push_back(inductionVariable);
688 regionArgs.front().type = type;
699 ForOp::ensureTerminator(*body, builder,
result.location);
709 p <<
" " << getInductionVar() <<
" = " <<
getLowerBound() <<
" to "
714 p <<
" : " << t <<
' ';
721LogicalResult ForOp::verifyRegions() {
724 if (getBody()->getNumArguments() != 1)
725 return emitOpError(
"expected body to have a single block argument for the "
726 "induction variable");
730 "expected induction variable to be same type as bounds and step");
741 auto fnAttr = getCalleeAttr();
743 return emitOpError(
"requires a 'callee' symbol reference attribute");
746 return emitOpError() <<
"'" << fnAttr.getValue()
747 <<
"' does not reference a valid function";
753FunctionType CallOp::getCalleeType() {
754 return FunctionType::get(
getContext(), getOperandTypes(), getResultTypes());
764 auto fnAttr = getSymNameAttr();
766 return emitOpError(
"requires a 'sym_name' symbol reference attribute");
769 return emitOpError() <<
"'" << fnAttr.getValue()
770 <<
"' does not reference a valid function";
784 state.
addAttribute(getFunctionTypeAttrName(state.
name), TypeAttr::get(type));
788 if (argAttrs.empty())
790 assert(type.getNumInputs() == argAttrs.size());
792 builder, state, argAttrs, {},
793 getArgAttrsAttrName(state.
name), getResAttrsAttrName(state.
name));
804 getFunctionTypeAttrName(
result.name), buildFuncType,
805 getArgAttrsAttrName(
result.name), getResAttrsAttrName(
result.name));
810 p, *
this,
false, getFunctionTypeAttrName(),
811 getArgAttrsAttrName(), getResAttrsAttrName());
814LogicalResult FuncOp::verify() {
815 if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {
816 return emitOpError(
"cannot have lvalue type as argument");
819 if (getNumResults() > 1)
820 return emitOpError(
"requires zero or exactly one result, but has ")
823 if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
824 return emitOpError(
"cannot return array type");
833LogicalResult ReturnOp::verify() {
834 auto function = cast<FuncOp>((*this)->getParentOp());
838 return emitOpError(
"has ")
840 << function.getName() <<
") returns " << function.getNumResults();
842 if (function.getNumResults() == 1)
843 if (getOperand().
getType() != function.getResultTypes()[0])
844 return emitError() <<
"type of the return operand ("
845 << getOperand().getType()
846 <<
") doesn't match function result type ("
847 << function.getResultTypes()[0] <<
")"
848 <<
" in function @" << function.getName();
857 bool addThenBlock,
bool addElseBlock) {
858 assert((!addElseBlock || addThenBlock) &&
859 "must not create else block w/o then block");
873 bool withElseRegion) {
883 if (withElseRegion) {
891 assert(thenBuilder &&
"the builder callback for 'then' must be present");
898 thenBuilder(builder,
result.location);
904 elseBuilder(builder,
result.location);
910 result.regions.reserve(2);
939 bool printBlockTerminators =
false;
941 p <<
" " << getCondition();
945 printBlockTerminators);
948 Region &elseRegion = getElseRegion();
949 if (!elseRegion.
empty()) {
953 printBlockTerminators);
975 Region *elseRegion = &this->getElseRegion();
976 if (elseRegion->
empty())
989 FoldAdaptor adaptor(operands, *
this);
990 auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());
991 if (!boolAttr || boolAttr.getValue())
992 regions.emplace_back(&getThenRegion());
995 if (!boolAttr || !boolAttr.getValue()) {
996 if (!getElseRegion().empty())
997 regions.emplace_back(&getElseRegion());
1003void IfOp::getRegionInvocationBounds(
1006 if (
auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {
1009 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
1010 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
1013 invocationBounds.assign(2, {0, 1});
1022 bool standardInclude = getIsStandardInclude();
1025 if (standardInclude)
1027 p <<
"\"" << getInclude() <<
"\"";
1028 if (standardInclude)
1043 <<
"expected trailing '>' for standard include";
1045 if (standardInclude)
1046 result.addAttribute(
"is_standard_include",
1057LogicalResult emitc::LiteralOp::verify() {
1058 if (getValue().empty())
1059 return emitOpError() <<
"value must not be empty";
1067LogicalResult MemberOp::verify() {
1068 Type operandType = getOperand().getType();
1069 Type resultType = getResult().getType();
1070 bool resultIsWritable = isa<emitc::LValueType, emitc::ArrayType>(resultType);
1080 if (isa<emitc::LValueType>(operandType) && !resultIsWritable)
1081 return emitOpError(
"lvalues must return lvalues or arrays");
1083 if (!isa<emitc::LValueType>(operandType) && resultIsWritable)
1084 return emitOpError(
"non-lvalues cannot return lvalues or arrays");
1093LogicalResult SubOp::verify() {
1094 Type lhsType = getLhs().getType();
1095 Type rhsType = getRhs().getType();
1096 Type resultType = getResult().getType();
1098 if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))
1099 return emitOpError(
"rhs can only be a pointer if lhs is a pointer");
1101 if (isa<emitc::PointerType>(lhsType) &&
1102 !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))
1103 return emitOpError(
"requires that rhs is an integer, pointer or of opaque "
1104 "type if lhs is a pointer");
1106 if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&
1107 !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))
1108 return emitOpError(
"requires that the result is an integer, ptrdiff_t or "
1109 "of opaque type if lhs and rhs are pointers");
1117LogicalResult emitc::VariableOp::verify() {
1125LogicalResult emitc::YieldOp::verify() {
1130 return emitOpError() <<
"yields a value not returned by parent";
1133 return emitOpError() <<
"does not yield a value to be returned by parent";
1135 if (
result && isa<emitc::LValueType>(
result.getType()) &&
1136 !isa<ExpressionOp>(containingOp))
1137 return emitOpError() <<
"yielding lvalues is not supported for this op";
1146LogicalResult emitc::SubscriptOp::verify() {
1148 if (
auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().
getType())) {
1150 if (
getIndices().size() != (
size_t)arrayType.getRank()) {
1151 return emitOpError() <<
"on array operand requires number of indices ("
1153 <<
") to match the rank of the array type ("
1154 << arrayType.getRank() <<
")";
1157 for (
unsigned i = 0, e =
getIndices().size(); i != e; ++i) {
1160 return emitOpError() <<
"on array operand requires index operand " << i
1161 <<
" to be integer-like, but got " << type;
1165 Type elementType = arrayType.getElementType();
1167 if (elementType != resultType) {
1168 return emitOpError() <<
"on array operand requires element type ("
1169 << elementType <<
") and result type (" << resultType
1176 if (
auto pointerType =
1177 llvm::dyn_cast<emitc::PointerType>(getValue().
getType())) {
1180 return emitOpError()
1181 <<
"on pointer operand requires one index operand, but got "
1187 return emitOpError() <<
"on pointer operand requires index operand to be "
1188 "integer-like, but got "
1192 Type pointeeType = pointerType.getPointee();
1194 if (pointeeType != resultType) {
1195 return emitOpError() <<
"on pointer operand requires pointee type ("
1196 << pointeeType <<
") and result type (" << resultType
1211LogicalResult emitc::VerbatimOp::verify() {
1213 return this->emitOpError();
1215 FailureOr<SmallVector<ReplacementItem>> fmt =
1220 size_t numPlaceholders = llvm::count_if(*fmt, [](
ReplacementItem &item) {
1221 return std::holds_alternative<Placeholder>(item);
1224 if (numPlaceholders != getFmtArgs().size()) {
1225 return emitOpError()
1226 <<
"requires operands for each placeholder in the format string";
1231FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {
1233 return ::parseFormatString(getValue(), getFmtArgs());
1240#include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"
1246#define GET_ATTRDEF_CLASSES
1247#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
1253#define GET_TYPEDEF_CLASSES
1254#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
1275 if (!isValidElementType(elementType))
1276 return parser.
emitError(typeLoc,
"invalid array element type '")
1277 << elementType <<
"'",
1281 return parser.
getChecked<ArrayType>(dimensions, elementType);
1284void emitc::ArrayType::print(
AsmPrinter &printer)
const {
1287 printer << dim <<
'x';
1293LogicalResult emitc::ArrayType::verify(
1297 return emitError() <<
"shape must not be empty";
1301 return emitError() <<
"dimensions must have non-negative size";
1305 return emitError() <<
"element type must not be none";
1307 if (!isValidElementType(elementType))
1308 return emitError() <<
"invalid array element type";
1315 Type elementType)
const {
1317 return emitc::ArrayType::get(
getShape(), elementType);
1318 return emitc::ArrayType::get(*
shape, elementType);
1325LogicalResult mlir::emitc::LValueType::verify(
1332 <<
"!emitc.lvalue must wrap supported emitc type, but got " << value;
1334 if (llvm::isa<emitc::ArrayType>(value))
1335 return emitError() <<
"!emitc.lvalue cannot wrap !emitc.array type";
1344LogicalResult mlir::emitc::OpaqueType::verify(
1346 llvm::StringRef value) {
1347 if (value.empty()) {
1348 return emitError() <<
"expected non empty string in !emitc.opaque type";
1350 if (value.back() ==
'*') {
1351 return emitError() <<
"pointer not allowed as outer type with "
1352 "!emitc.opaque, use !emitc.ptr instead";
1361LogicalResult mlir::emitc::PointerType::verify(
1363 if (llvm::isa<emitc::LValueType>(value))
1364 return emitError() <<
"pointers to lvalues are not allowed";
1383 if (
auto array = llvm::dyn_cast<ArrayType>(type))
1384 return RankedTensorType::get(array.getShape(), array.getElementType());
1395 typeAttr = TypeAttr::get(type);
1403 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1406 <<
"initial value should be a integer, float, elements or opaque "
1411LogicalResult GlobalOp::verify() {
1413 return emitOpError(
"expected valid emitc type");
1415 if (getInitialValue().has_value()) {
1416 Attribute initValue = getInitialValue().value();
1419 if (
auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1420 auto arrayType = llvm::dyn_cast<ArrayType>(
getType());
1422 return emitOpError(
"expected array type, but got ") <<
getType();
1424 Type initType = elementsAttr.getType();
1426 if (initType != tensorType) {
1427 return emitOpError(
"initial value expected to be of type ")
1428 <<
getType() <<
", but was of type " << initType;
1430 }
else if (
auto intAttr = dyn_cast<IntegerAttr>(initValue)) {
1431 if (intAttr.getType() !=
getType()) {
1432 return emitOpError(
"initial value expected to be of type ")
1433 <<
getType() <<
", but was of type " << intAttr.getType();
1435 }
else if (
auto floatAttr = dyn_cast<FloatAttr>(initValue)) {
1436 if (floatAttr.getType() !=
getType()) {
1437 return emitOpError(
"initial value expected to be of type ")
1438 <<
getType() <<
", but was of type " << floatAttr.getType();
1440 }
else if (!isa<emitc::OpaqueAttr>(initValue)) {
1441 return emitOpError(
"initial value should be a integer, float, elements "
1442 "or opaque attribute, but got ")
1446 if (getStaticSpecifier() && getExternSpecifier()) {
1447 return emitOpError(
"cannot have both static and extern specifiers");
1462 return emitOpError(
"'")
1463 << getName() <<
"' does not reference a valid emitc.global";
1465 Type resultType = getResult().getType();
1466 Type globalType = global.getType();
1469 if (llvm::isa<ArrayType>(globalType)) {
1470 if (globalType != resultType)
1471 return emitOpError(
"on array type expects result type ")
1472 << resultType <<
" to match type " << globalType
1473 <<
" of the global @" << getName();
1478 auto lvalueType = dyn_cast<LValueType>(resultType);
1480 return emitOpError(
"on non-array type expects result type to be an "
1481 "lvalue type for the global @")
1483 if (lvalueType.getValueType() != globalType)
1484 return emitOpError(
"on non-array type expects result inner type ")
1485 << lvalueType.getValueType() <<
" to match type " << globalType
1486 <<
" of the global @" << getName();
1501 Region ®ion = *caseRegions.emplace_back(std::make_unique<Region>());
1505 caseValues.push_back(value);
1514 for (
auto [value, region] : llvm::zip(cases.
asArrayRef(), caseRegions)) {
1516 p <<
"case " << value <<
' ';
1522 const Twine &name) {
1523 auto yield = dyn_cast<emitc::YieldOp>(region.
front().
back());
1525 return op.emitOpError(
"expected region to end with emitc.yield, but got ")
1528 if (yield.getNumOperands() != 0) {
1529 return (op.emitOpError(
"expected each region to return ")
1530 <<
"0 values, but " << name <<
" returns "
1531 << yield.getNumOperands())
1532 .attachNote(yield.getLoc())
1533 <<
"see yield operation here";
1539LogicalResult emitc::SwitchOp::verify() {
1541 return emitOpError(
"unsupported type ") << getArg().getType();
1543 if (getCases().size() != getCaseRegions().size()) {
1544 return emitOpError(
"has ")
1545 << getCaseRegions().size() <<
" case regions but "
1546 << getCases().size() <<
" case values";
1550 for (
int64_t value : getCases())
1551 if (!valueSet.insert(value).second)
1552 return emitOpError(
"has duplicate case value: ") << value;
1557 for (
auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
1564unsigned emitc::SwitchOp::getNumCases() {
return getCases().size(); }
1566Block &emitc::SwitchOp::getDefaultBlock() {
return getDefaultRegion().
front(); }
1568Block &emitc::SwitchOp::getCaseBlock(
unsigned idx) {
1569 assert(idx < getNumCases() &&
"case index out-of-bounds");
1570 return getCaseRegions()[idx].front();
1573void SwitchOp::getSuccessorRegions(
1575 llvm::append_range(successors, getRegions());
1581 Type type = attr.getType();
1583 return attr.getInt();
1585 return attr.getSInt();
1587 return static_cast<int64_t>(attr.getUInt());
1588 return std::nullopt;
1591void SwitchOp::getEntrySuccessorRegions(
1594 FoldAdaptor adaptor(operands, *
this);
1597 auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
1599 llvm::append_range(successors, getRegions());
1606 llvm::append_range(successors, getRegions());
1612 for (
auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
1613 if (caseValue == *argValue) {
1614 successors.emplace_back(&caseRegion);
1618 successors.emplace_back(&getDefaultRegion());
1621void SwitchOp::getRegionInvocationBounds(
1623 auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
1624 if (!operandValue) {
1631 if (!maybeIntValue) {
1637 unsigned liveIndex = getNumRegions() - 1;
1638 const auto *iteratorToInt = llvm::find(getCases(), *maybeIntValue);
1640 liveIndex = iteratorToInt != getCases().end()
1641 ? std::distance(getCases().begin(), iteratorToInt)
1644 for (
unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
1646 bounds.emplace_back(0, regIndex == liveIndex);
1673 if (
auto array = llvm::dyn_cast<ArrayType>(type))
1674 return RankedTensorType::get(array.getShape(), array.getElementType());
1685 typeAttr = TypeAttr::get(type);
1693 if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(
1696 <<
"initial value should be a integer, float, elements or opaque "
1701LogicalResult FieldOp::verify() {
1703 return emitOpError(
"expected valid emitc type");
1706 if (!parentOp || !isa<emitc::ClassOp>(parentOp))
1707 return emitOpError(
"field must be nested within an emitc.class operation");
1709 StringAttr symName = getSymNameAttr();
1710 if (!symName || symName.getValue().empty())
1711 return emitOpError(
"field must have a non-empty symbol name");
1725 return emitOpError(
"field '")
1726 << fieldNameAttr <<
"' not found in the class";
1728 Type getFieldResultType = getResult().getType();
1729 Type fieldType = fieldOp.getType();
1731 if (fieldType != getFieldResultType)
1732 return emitOpError(
"result type ")
1733 << getFieldResultType <<
" does not match field '" << fieldNameAttr
1734 <<
"' type " << fieldType;
1749 getOperation()->getDiscardableAttrDictionary().getValue());
1752LogicalResult emitc::DoOp::verify() {
1753 Block &condBlock = getConditionRegion().
front();
1757 "condition region must contain exactly two operations: "
1758 "'emitc.expression' followed by 'emitc.yield', but found ")
1762 auto exprOp = dyn_cast<emitc::ExpressionOp>(first);
1764 return emitOpError(
"expected first op in condition region to be "
1765 "'emitc.expression', but got ")
1768 if (!exprOp.getResult().getType().isInteger(1))
1769 return emitOpError(
"emitc.expression in condition region must return "
1770 "'i1', but returns ")
1771 << exprOp.getResult().getType();
1774 auto condYield = dyn_cast<emitc::YieldOp>(last);
1776 return emitOpError(
"expected last op in condition region to be "
1777 "'emitc.yield', but got ")
1780 if (condYield.getNumOperands() != 1)
1781 return emitOpError(
"expected condition region to return 1 value, but "
1783 << condYield.getNumOperands() <<
" values";
1785 if (condYield.getOperand(0) != exprOp.getResult())
1786 return emitError(
"'emitc.yield' must return result of "
1787 "'emitc.expression' from this condition region");
1791 return emitOpError(
"body region must not contain terminator");
1804 if (bodyRegion->
empty())
1814#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"
1816#define GET_OP_CLASSES
1817#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
static Value getPointer(Location loc, Value value, ConversionPatternRewriter &rewriter)
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
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,...
static LogicalResult verifyInitializationAttribute(Operation *op, Attribute value)
Check that the type of the initial value is compatible with the operations result type.
static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, const Twine &name)
static ParseResult parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
static Type getInitializerTypeForField(Type type)
static ParseResult parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
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.
static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, TypeAttr type, Attribute initialValue)
static LogicalResult verifyAssignmentOp(AssignmentOp op)
static ParseResult parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases, SmallVectorImpl< std::unique_ptr< Region > > &caseRegions)
Parse the case regions and values.
static LogicalResult verifyOpaqueCallCommon(Operation *op, StringRef callee, std::optional< ArrayAttr > args, std::optional< ArrayAttr > templateArgs, TypeRange resultTypes, size_t numArgsOperands)
static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op, TypeAttr type, Attribute initialValue)
static void printSwitchCases(OpAsmPrinter &p, Operation *op, DenseI64ArrayAttr cases, RegionRange caseRegions)
Print the case regions and values.
static Type getInitializerTypeForGlobal(Type type)
static Type getValueType(Attribute attr)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
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.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
BlockArgListType getArguments()
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
This class is a general helper class for creating context-global objects like types,...
DenseI64ArrayAttr getDenseI64ArrayAttr(ArrayRef< int64_t > values)
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
IntegerType getIntegerType(unsigned width)
StringAttr getStringAttr(const Twine &bytes)
NamedAttribute getNamedAttr(StringRef name, Attribute val)
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'.
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...
MLIRContext is the top-level object for a collection of MLIR operations.
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 ®ion, 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 ®ion, ValueRange namesToUse)=0
Renumber the arguments for the specified region to the same names as the SSA values in namesToUse.
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with 'attribute...
void printOperands(OperandRange operands)
Print a comma separated range of operation operands out of line to avoid instantiating the range iter...
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.
This class helps build Operations.
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.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents a single result from folding an operation.
type_range getType() const
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
OperationName getName()
The name of an operation is the key identifier for it.
operand_range getOperands()
Returns an iterator on the underlying Value's.
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.
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.
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.
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...
static DerivedEffect * get()
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,...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
ArrayRef< T > asArrayRef() const
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
LogicalResult verifyCallOpInterface(CallOpInterface call, TypeRange argumentTypes, TypeRange resultTypes)
Verify that the forwarded operands and results of call are in a 1:1 relationship with the given argum...
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.
std::variant< StringRef, Placeholder > ReplacementItem
bool isFundamentalType(mlir::Type type)
Determines whether type is a valid fundamental C++ type in EmitC.
bool isSupportedFloatType(mlir::Type type)
Determines whether type is a valid floating-point type in EmitC.
bool isSupportedEmitCType(mlir::Type type)
Determines whether type is valid in EmitC.
bool isPointerWideType(mlir::Type type)
Determines whether type is a emitc.size_t/ssize_t type.
bool isIntegerIndexOrOpaqueType(Type type)
Determines whether type is integer like, i.e.
bool isSupportedIntegerType(mlir::Type type)
Determines whether type is a valid integer type in EmitC.
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.
Include the generated interface declarations.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::SetVector< T, Vector, Set, N > SetVector
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.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref
UnresolvedOperand ssaName
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.