25#include "llvm/ADT/SetOperations.h"
26#include "llvm/ADT/SmallVectorExtras.h"
27#include "llvm/ADT/TypeSwitch.h"
28#include "llvm/Support/raw_ostream.h"
34#include "mlir/Dialect/Shape/IR/ShapeOpsDialect.cpp.inc"
37#include "ShapeCanonicalization.inc"
41 return RankedTensorType::get({rank}, IndexType::get(ctx));
45 auto ranked = llvm::dyn_cast<RankedTensorType>(type);
46 return ranked && ranked.getRank() == 1 && ranked.getElementType().isIndex();
52 auto type = llvm::cast<ShapedType>(inputOp.getArg().getType());
55 llvm::append_range(shapeValues, type.getShape());
60 llvm::append_range(shapeValues, attr.getValues<
int64_t>());
67 return llvm::any_of(operandTypes,
68 llvm::IsaPred<SizeType, ShapeType, ValueShapeType>);
75 if (!llvm::isa<SizeType>(resultTy))
77 <<
"if at least one of the operands can hold error values then "
78 "the result must be of type `size` to propagate them";
87 if (!llvm::isa<ShapeType>(resultTy))
89 <<
"if at least one of the operands can hold error values then "
90 "the result must be of type `shape` to propagate them";
95template <
typename... Ty>
97 return typeRange.size() == 1 && llvm::isa<Ty...>(typeRange.front());
100template <
typename... Ty,
typename... ranges>
111struct ShapeInlinerInterface :
public DialectInlinerInterface {
112 using DialectInlinerInterface::DialectInlinerInterface;
117 IRMapping &)
const final {
125 IRMapping &)
const final {
131void ShapeDialect::initialize() {
134#include "mlir/Dialect/Shape/IR/ShapeOps.cpp.inc"
137#define GET_TYPEDEF_LIST
138#include "mlir/Dialect/Shape/IR/ShapeOpsTypes.cpp.inc"
140 addInterfaces<ShapeInlinerInterface>();
144 allowUnknownOperations();
145 declarePromisedInterfaces<bufferization::BufferizableOpInterface, AssumingOp,
152 if (
auto poison = dyn_cast<ub::PoisonAttr>(value))
153 return ub::PoisonOp::create(builder, loc, type, poison);
156 return ConstShapeOp::create(builder, loc, type,
157 llvm::cast<DenseIntElementsAttr>(value));
158 if (llvm::isa<SizeType>(type))
159 return ConstSizeOp::create(builder, loc, type,
160 llvm::cast<IntegerAttr>(value));
161 if (llvm::isa<WitnessType>(type))
162 return ConstWitnessOp::create(builder, loc, type,
163 llvm::cast<BoolAttr>(value));
165 return arith::ConstantOp::materialize(builder, value, type, loc);
168LogicalResult ShapeDialect::verifyOperationAttribute(
Operation *op,
171 if (attribute.
getName() ==
"shape.lib") {
174 "shape.lib attribute may only be on op implementing SymbolTable");
176 if (
auto symbolRef = llvm::dyn_cast<SymbolRefAttr>(attribute.
getValue())) {
179 return op->
emitError(
"shape function library ")
180 << symbolRef <<
" not found";
181 return isa<shape::FunctionLibraryOp>(symbol)
184 << symbolRef <<
" required to be shape function library";
187 if (
auto arr = llvm::dyn_cast<ArrayAttr>(attribute.
getValue())) {
191 for (
auto it : arr) {
192 if (!llvm::isa<SymbolRefAttr>(it))
194 "only SymbolRefAttr allowed in shape.lib attribute array");
196 auto shapeFnLib = dyn_cast_or_null<shape::FunctionLibraryOp>(
200 << it <<
" does not refer to FunctionLibraryOp";
201 for (
auto mapping : shapeFnLib.getMapping()) {
202 if (!key.insert(mapping.getName()).second) {
203 return op->
emitError(
"only one op to shape mapping allowed, found "
205 << mapping.getName() <<
"`";
212 return op->
emitError(
"only SymbolRefAttr or array of SymbolRefAttrs "
213 "allowed as shape.lib attribute");
226 if (adaptor.getInputs().back())
227 return adaptor.getInputs().back();
237 result.regions.reserve(1);
254 AssumingOp::ensureTerminator(*doRegion, parser.
getBuilder(),
result.location);
263 bool yieldsResults = !getResults().empty();
265 p <<
" " << getWitness();
267 p <<
" -> (" << getResultTypes() <<
")";
278 using OpRewritePattern<AssumingOp>::OpRewritePattern;
280 LogicalResult matchAndRewrite(AssumingOp op,
281 PatternRewriter &rewriter)
const override {
282 auto witness = op.getWitness().getDefiningOp<ConstWitnessOp>();
283 if (!witness || !witness.getPassingAttr())
286 AssumingOp::inlineRegionIntoParent(op, rewriter);
292 using OpRewritePattern<AssumingOp>::OpRewritePattern;
294 LogicalResult matchAndRewrite(AssumingOp op,
295 PatternRewriter &rewriter)
const override {
296 Block *body = op.getBody();
297 auto yieldOp = llvm::cast<AssumingYieldOp>(body->
getTerminator());
300 SmallVector<Value, 4> newYieldOperands;
301 for (
auto [opResult, yieldOperand] :
302 llvm::zip(op.getResults(), yieldOp.getOperands())) {
303 if (!opResult.getUses().empty()) {
304 newYieldOperands.push_back(yieldOperand);
309 if (newYieldOperands.size() == yieldOp->getNumOperands())
318 auto newOp = AssumingOp::create(
319 rewriter, op.getLoc(), newYieldOp->getOperandTypes(), op.getWitness());
320 newOp.getDoRegion().takeBody(op.getDoRegion());
323 SmallVector<Value, 4> replacementValues;
324 auto src = newOp.getResults().begin();
325 for (
auto it : op.getResults()) {
326 if (it.getUses().empty())
327 replacementValues.push_back(
nullptr);
329 replacementValues.push_back(*src++);
331 rewriter.
replaceOp(op, replacementValues);
339 patterns.
add<AssumingOpRemoveUnusedResults, AssumingWithTrue>(context);
343void AssumingOp::getSuccessorRegions(
360void AssumingOp::inlineRegionIntoParent(AssumingOp &op,
363 auto *assumingBlock = op.getBody();
365 auto *blockAfterAssuming =
366 rewriter.
splitBlock(blockBeforeAssuming, initPosition);
369 auto &yieldOp = assumingBlock->
back();
371 rewriter.
replaceOp(op, yieldOp.getOperands());
376 rewriter.
mergeBlocks(assumingBlock, blockBeforeAssuming);
377 rewriter.
mergeBlocks(blockAfterAssuming, blockBeforeAssuming);
380void AssumingOp::build(
385 result.addOperands(witness);
391 AssumingYieldOp::create(builder,
result.location, yieldValues);
394 for (
Value v : yieldValues)
395 assumingTypes.push_back(v.getType());
396 result.addTypes(assumingTypes);
403LogicalResult mlir::shape::AddOp::inferReturnTypes(
404 MLIRContext *context, std::optional<Location> location,
406 if (llvm::isa<SizeType>(adaptor.getLhs().getType()) ||
407 llvm::isa<SizeType>(adaptor.getRhs().getType()))
408 inferredReturnTypes.assign({SizeType::get(context)});
410 inferredReturnTypes.assign({IndexType::get(context)});
419OpFoldResult mlir::shape::AddOp::fold(FoldAdaptor adaptor) {
425 adaptor.getOperands(),
426 [](APInt a,
const APInt &
b) { return std::move(a) + b; });
446 using OpRewritePattern<AssumingAllOp>::OpRewritePattern;
448 LogicalResult matchAndRewrite(AssumingAllOp op,
449 PatternRewriter &rewriter)
const override {
450 SmallVector<Value> operands;
452 for (Value operand : op.getInputs()) {
453 if (
auto assumeAll = operand.getDefiningOp<AssumingAllOp>())
454 operands.append(assumeAll.operand_begin(), assumeAll->operand_end());
456 operands.push_back(operand);
460 if (operands.size() == op.getNumOperands())
490struct AssumingAllOfCstrBroadcastable :
public OpRewritePattern<AssumingAllOp> {
491 using OpRewritePattern<AssumingAllOp>::OpRewritePattern;
493 LogicalResult matchAndRewrite(AssumingAllOp op,
494 PatternRewriter &rewriter)
const override {
497 for (Value operand : op.getInputs()) {
500 auto broadcastable = operand.getDefiningOp<CstrBroadcastableOp>();
504 operands.insert(broadcastable);
508 if (operands.size() <= 1)
512 SmallVector<std::pair<CstrBroadcastableOp, DenseSet<Value>>> shapes;
513 for (
auto cstr : operands) {
515 shapes.emplace_back(cstr, std::move(shapesSet));
519 llvm::sort(shapes, [](
auto a,
auto b) {
520 return a.first.getNumOperands() >
b.first.getNumOperands();
527 SmallVector<CstrBroadcastableOp> markedForErase;
529 for (
unsigned i = 0; i < shapes.size(); ++i) {
530 auto isSubset = [&](
auto pair) {
531 return llvm::set_is_subset(pair.second, shapes[i].second);
535 auto *it = std::remove_if(shapes.begin() + i + 1, shapes.end(), isSubset);
536 for (
auto *it0 = it; it0 < shapes.end(); ++it0)
537 markedForErase.push_back(it0->first);
538 shapes.erase(it, shapes.end());
542 if (markedForErase.empty())
546 SmallVector<Value> uniqueConstraints;
547 for (
auto &shape : shapes)
548 uniqueConstraints.push_back(shape.first.getResult());
554 for (
auto &op : markedForErase)
562struct AssumingAllToCstrEqCanonicalization
564 using OpRewritePattern<AssumingAllOp>::OpRewritePattern;
566 LogicalResult matchAndRewrite(AssumingAllOp op,
567 PatternRewriter &rewriter)
const override {
568 SmallVector<Value, 8> shapes;
569 for (Value w : op.getInputs()) {
570 auto cstrEqOp = w.getDefiningOp<CstrEqOp>();
573 bool disjointShapes = llvm::none_of(cstrEqOp.getShapes(), [&](Value s) {
574 return llvm::is_contained(shapes, s);
576 if (!shapes.empty() && !cstrEqOp.getShapes().empty() && disjointShapes)
578 shapes.append(cstrEqOp.getShapes().begin(), cstrEqOp.getShapes().end());
585template <
typename OpTy>
587 using OpRewritePattern<OpTy>::OpRewritePattern;
589 LogicalResult matchAndRewrite(OpTy op,
590 PatternRewriter &rewriter)
const override {
595 if (unique.size() < op.getNumOperands()) {
597 op, op->getResultTypes(), unique.takeVector(), op.getProperties(),
598 op->getDiscardableAttrDictionary().getValue());
610 .
add<MergeAssumingAllOps, AssumingAllOneOp,
611 AssumingAllOfCstrBroadcastable, AssumingAllToCstrEqCanonicalization,
612 RemoveDuplicateOperandsPattern<AssumingAllOp>>(context);
618 for (
int idx = adaptor.getInputs().size() - 1; idx >= 0; idx--) {
626 getOperation()->eraseOperand(idx);
629 if (!llvm::cast<BoolAttr>(a).getValue())
636LogicalResult AssumingAllOp::verify() {
639 return emitOpError(
"no operands specified");
649 if (getShapes().size() == 1) {
653 return getShapes().front();
657 dyn_cast_or_null<DenseIntElementsAttr>(adaptor.getShapes().front());
663 for (
auto next : adaptor.getShapes().drop_front()) {
664 auto nextAttr = dyn_cast_or_null<DenseIntElementsAttr>(next);
667 auto nextShape = llvm::to_vector<6>(nextAttr.getValues<
int64_t>());
676 std::copy(tmpShape.begin(), tmpShape.end(),
677 std::back_inserter(resultShape));
684LogicalResult BroadcastOp::verify() {
689template <
typename OpTy>
691 using OpRewritePattern<OpTy>::OpRewritePattern;
693 LogicalResult matchAndRewrite(OpTy op,
694 PatternRewriter &rewriter)
const override {
695 auto isPotentiallyNonEmptyShape = [](Value shape) {
696 if (
auto extentTensorTy =
697 llvm::dyn_cast<RankedTensorType>(shape.getType())) {
698 if (extentTensorTy.getDimSize(0) == 0)
701 if (
auto constShape = shape.getDefiningOp<ConstShapeOp>()) {
702 if (constShape.getShape().empty())
707 auto newOperands = llvm::filter_to_vector<8>(op->getOperands(),
708 isPotentiallyNonEmptyShape);
712 if (newOperands.empty()) {
719 if (newOperands.size() < op.getNumOperands()) {
721 op, op->getResultTypes(), newOperands, op.getProperties(),
722 op->getDiscardableAttrDictionary().getValue());
730struct BroadcastForwardSingleOperandPattern
732 using OpRewritePattern<BroadcastOp>::OpRewritePattern;
734 LogicalResult matchAndRewrite(BroadcastOp op,
735 PatternRewriter &rewriter)
const override {
736 if (op.getNumOperands() != 1)
742 auto loc = op.getLoc();
743 if (llvm::isa<ShapeType>(op.getType())) {
746 assert(!llvm::isa<ShapeType>(op.getType()) &&
748 "expect extent tensor cast");
750 tensor::CastOp::create(rewriter, loc, op.getType(),
replacement);
759struct BroadcastFoldConstantOperandsPattern
761 using OpRewritePattern<BroadcastOp>::OpRewritePattern;
763 LogicalResult matchAndRewrite(BroadcastOp op,
764 PatternRewriter &rewriter)
const override {
765 SmallVector<int64_t, 8> foldedConstantShape;
766 SmallVector<Value, 8> newShapeOperands;
767 for (Value shape : op.getShapes()) {
768 if (
auto constShape = shape.getDefiningOp<ConstShapeOp>()) {
769 SmallVector<int64_t, 8> newFoldedConstantShape;
772 llvm::to_vector<8>(constShape.getShape().getValues<int64_t>()),
773 newFoldedConstantShape)) {
774 foldedConstantShape = newFoldedConstantShape;
778 newShapeOperands.push_back(shape);
782 if (op.getNumOperands() - newShapeOperands.size() < 2)
785 auto foldedConstantOperandsTy = RankedTensorType::get(
786 {
static_cast<int64_t
>(foldedConstantShape.size())},
788 newShapeOperands.push_back(
789 ConstShapeOp::create(rewriter, op.getLoc(), foldedConstantOperandsTy,
792 op,
TypeRange{op.getType()}, newShapeOperands, op.getProperties(),
793 op->getDiscardableAttrDictionary().getValue());
798template <
typename OpTy>
799struct CanonicalizeCastExtentTensorOperandsPattern
801 using OpRewritePattern<OpTy>::OpRewritePattern;
803 LogicalResult matchAndRewrite(OpTy op,
804 PatternRewriter &rewriter)
const override {
806 bool anyChange =
false;
807 auto canonicalizeOperand = [&](Value operand) -> Value {
808 if (
auto castOp = operand.getDefiningOp<tensor::CastOp>()) {
810 bool isInformationLoosingCast =
811 llvm::cast<RankedTensorType>(castOp.getType()).isDynamicDim(0);
812 if (isInformationLoosingCast) {
814 return castOp.getSource();
820 llvm::map_to_vector<8>(op.getOperands(), canonicalizeOperand);
826 op, op->getResultTypes(), newOperands, op.getProperties(),
827 op->getDiscardableAttrDictionary().getValue());
832struct BroadcastConcretizeResultTypePattern
834 using OpRewritePattern<BroadcastOp>::OpRewritePattern;
836 LogicalResult matchAndRewrite(BroadcastOp op,
837 PatternRewriter &rewriter)
const override {
839 auto resultTy = llvm::dyn_cast<RankedTensorType>(op.getType());
840 if (!resultTy || !resultTy.isDynamicDim(0))
845 for (Value shape : op.getShapes()) {
846 if (
auto extentTensorTy =
847 llvm::dyn_cast<RankedTensorType>(shape.getType())) {
850 if (extentTensorTy.isDynamicDim(0))
852 maxRank = std::max(maxRank, extentTensorTy.getDimSize(0));
856 auto newOp = BroadcastOp::create(rewriter, op.getLoc(),
858 op.getShapes(),
nullptr);
867 patterns.
add<BroadcastConcretizeResultTypePattern,
868 BroadcastFoldConstantOperandsPattern,
869 BroadcastForwardSingleOperandPattern,
870 CanonicalizeCastExtentTensorOperandsPattern<BroadcastOp>,
871 RemoveDuplicateOperandsPattern<BroadcastOp>,
872 RemoveEmptyShapeOperandsPattern<BroadcastOp>>(context);
880 if (!adaptor.getLhs() || !adaptor.getRhs())
882 auto lhsShape = llvm::to_vector<6>(
883 llvm::cast<DenseIntElementsAttr>(adaptor.getLhs()).getValues<
int64_t>());
884 auto rhsShape = llvm::to_vector<6>(
885 llvm::cast<DenseIntElementsAttr>(adaptor.getRhs()).getValues<
int64_t>());
887 resultShape.append(lhsShape.begin(), lhsShape.end());
888 resultShape.append(rhsShape.begin(), rhsShape.end());
901 interleaveComma(
getShape().getValues<int64_t>(), p);
916 auto extentsArray = llvm::dyn_cast<ArrayAttr>(extentsRaw);
921 IntegerAttr attr = llvm::dyn_cast<IntegerAttr>(extent);
924 ints.push_back(attr.getInt());
931 result.types.push_back(resultTy);
935OpFoldResult ConstShapeOp::fold(FoldAdaptor) {
return getShapeAttr(); }
939 patterns.
add<TensorCastConstShape>(context);
942LogicalResult mlir::shape::ConstShapeOp::inferReturnTypes(
943 MLIRContext *context, std::optional<Location> location,
946 const Properties prop = adaptor.getProperties();
947 inferredReturnTypes.assign({RankedTensorType::get(
948 {
static_cast<int64_t>(prop.shape.size())},
b.getIndexType())});
952bool mlir::shape::ConstShapeOp::isCompatibleReturnTypes(
TypeRange l,
954 if (l.size() != 1 || r.size() != 1)
957 Type lhs = l.front();
958 Type rhs = r.front();
960 if (llvm::isa<ShapeType>(lhs) || llvm::isa<ShapeType>(rhs))
970void CstrBroadcastableOp::getCanonicalizationPatterns(
975 patterns.
add<CanonicalizeCastExtentTensorOperandsPattern<CstrBroadcastableOp>,
976 CstrBroadcastableEqOps,
977 RemoveDuplicateOperandsPattern<CstrBroadcastableOp>,
978 RemoveEmptyShapeOperandsPattern<CstrBroadcastableOp>>(context);
984 bool nonScalarSeen =
false;
986 if (!a || llvm::cast<DenseIntElementsAttr>(a).
getNumElements() != 0) {
989 nonScalarSeen =
true;
995OpFoldResult CstrBroadcastableOp::fold(FoldAdaptor adaptor) {
1002 for (
const auto &operand : adaptor.getShapes()) {
1005 extents.push_back(llvm::to_vector<6>(
1006 llvm::cast<DenseIntElementsAttr>(operand).getValues<int64_t>()));
1016 for (
auto shapeValue : getShapes()) {
1017 extents.emplace_back();
1030LogicalResult CstrBroadcastableOp::verify() {
1033 return emitOpError(
"required at least 2 input shapes");
1044 patterns.
add<CstrEqEqOps>(context);
1048 if (llvm::all_of(adaptor.getShapes(), [&](
Attribute a) {
1049 return a && a == adaptor.getShapes().front();
1068OpFoldResult ConstSizeOp::fold(FoldAdaptor) {
return getValueAttr(); }
1070void ConstSizeOp::getAsmResultNames(
1073 llvm::raw_svector_ostream os(buffer);
1074 os <<
"c" << getValue();
1075 setNameFn(getResult(), os.str());
1082OpFoldResult ConstWitnessOp::fold(FoldAdaptor) {
return getPassingAttr(); }
1089 return adaptor.getPred();
1096std::optional<int64_t> DimOp::getConstantIndex() {
1097 if (
auto constSizeOp =
getIndex().getDefiningOp<ConstSizeOp>())
1098 return constSizeOp.getValue().getLimitedValue();
1099 if (
auto constantOp =
getIndex().getDefiningOp<arith::ConstantOp>())
1100 return llvm::cast<IntegerAttr>(constantOp.getValue()).getInt();
1101 return std::nullopt;
1105 Type valType = getValue().getType();
1106 auto valShapedType = llvm::dyn_cast<ShapedType>(valType);
1107 if (!valShapedType || !valShapedType.hasRank())
1109 std::optional<int64_t>
index = getConstantIndex();
1110 if (!
index.has_value())
1112 if (
index.value() < 0 ||
index.value() >= valShapedType.getRank())
1114 auto extent = valShapedType.getDimSize(*
index);
1115 if (ShapedType::isDynamic(extent))
1117 return IntegerAttr::get(IndexType::get(
getContext()), extent);
1120LogicalResult mlir::shape::DimOp::inferReturnTypes(
1121 MLIRContext *context, std::optional<Location> location,
1123 inferredReturnTypes.assign({adaptor.getIndex().getType()});
1136 auto lhs = llvm::dyn_cast_if_present<IntegerAttr>(adaptor.getLhs());
1139 auto rhs = llvm::dyn_cast_if_present<IntegerAttr>(adaptor.getRhs());
1140 if (!rhs || rhs.getValue().isZero())
1145 APInt quotient, remainder;
1146 APInt::sdivrem(lhs.getValue(), rhs.getValue(), quotient, remainder);
1147 if (quotient.isNegative() && !remainder.isZero()) {
1152 return IntegerAttr::get(indexTy, quotient);
1155LogicalResult mlir::shape::DivOp::inferReturnTypes(
1156 MLIRContext *context, std::optional<Location> location,
1158 if (llvm::isa<SizeType>(adaptor.getLhs().getType()) ||
1159 llvm::isa<SizeType>(adaptor.getRhs().getType()))
1160 inferredReturnTypes.assign({SizeType::get(context)});
1162 inferredReturnTypes.assign({IndexType::get(context)});
1178 bool allSame =
true;
1179 if (!adaptor.getShapes().empty() && !adaptor.getShapes().front())
1181 for (
Attribute operand : adaptor.getShapes().drop_front()) {
1184 allSame = allSame && operand == adaptor.getShapes().front();
1203 patterns.
add<SizeToIndexToSizeCanonicalization>(context);
1212 for (
Attribute attr : adaptor.getExtents()) {
1213 auto intAttr = llvm::dyn_cast_if_present<IntegerAttr>(attr);
1216 extents.push_back(intAttr.getInt());
1228 result.getOrAddProperties<Properties>().sym_name =
1232FuncOp FunctionLibraryOp::getShapeFunction(
Operation *op) {
1233 auto attr = llvm::dyn_cast_or_null<FlatSymbolRefAttr>(
1237 return lookupSymbol<FuncOp>(attr);
1240ParseResult FunctionLibraryOp::parse(
OpAsmParser &parser,
1243 StringAttr nameAttr;
1251 auto *bodyRegion =
result.addRegion();
1258 DictionaryAttr mappingAttr;
1270 (*this)->getDiscardableAttrDictionary().getValue());
1282FuncOp FuncOp::create(
Location location, StringRef name, FunctionType type,
1286 FuncOp::build(builder, state, name, type, attrs);
1289FuncOp FuncOp::create(
Location location, StringRef name, FunctionType type,
1294FuncOp FuncOp::create(
Location location, StringRef name, FunctionType type,
1297 FuncOp
func = create(location, name, type, attrs);
1298 func.setAllArgAttrs(argAttrs);
1308 TypeAttr::get(type));
1312 if (argAttrs.empty())
1314 assert(type.getNumInputs() == argAttrs.size());
1316 builder, state, argAttrs, {},
1317 getArgAttrsAttrName(state.
name), getResAttrsAttrName(state.
name));
1321 auto buildFuncType =
1324 std::string &) {
return builder.
getFunctionType(argTypes, results); };
1328 getFunctionTypeAttrName(
result.name), buildFuncType,
1329 getArgAttrsAttrName(
result.name), getResAttrsAttrName(
result.name));
1334 p, *
this,
false, getFunctionTypeAttrName(),
1335 getArgAttrsAttrName(), getResAttrsAttrName());
1342std::optional<int64_t> GetExtentOp::getConstantDim() {
1343 if (
auto constSizeOp = getDim().getDefiningOp<ConstSizeOp>())
1344 return constSizeOp.getValue().getLimitedValue();
1345 if (
auto constantOp = getDim().getDefiningOp<arith::ConstantOp>())
1346 return llvm::cast<IntegerAttr>(constantOp.getValue()).getInt();
1347 return std::nullopt;
1352 llvm::dyn_cast_if_present<DenseIntElementsAttr>(adaptor.getShape());
1355 std::optional<int64_t> dim = getConstantDim();
1356 if (!dim.has_value())
1358 if (dim.value() >= elements.getNumElements())
1360 return elements.getValues<
Attribute>()[(uint64_t)dim.value()];
1365 auto loc =
result.location;
1367 if (llvm::isa<ShapeType>(
shape.getType())) {
1368 Value dim = ConstSizeOp::create(builder, loc, dimAttr);
1377LogicalResult mlir::shape::GetExtentOp::inferReturnTypes(
1378 MLIRContext *context, std::optional<Location> location,
1380 inferredReturnTypes.assign({IndexType::get(context)});
1384bool mlir::shape::GetExtentOp::isCompatibleReturnTypes(
TypeRange l,
1398 patterns.
add<RemoveDuplicateOperandsPattern<IsBroadcastableOp>>(context);
1401OpFoldResult IsBroadcastableOp::fold(FoldAdaptor adaptor) {
1403 if (adaptor.getShapes().size() < 2) {
1414LogicalResult mlir::shape::MeetOp::inferReturnTypes(
1415 MLIRContext *context, std::optional<Location> location,
1417 if (adaptor.getOperands().empty())
1420 auto isShapeType = [](
Type arg) {
1421 if (llvm::isa<ShapeType>(arg))
1428 for (
auto t : drop_begin(types)) {
1430 if (!llvm::isa<ShapeType, SizeType>(l))
1434 if (llvm::isa<SizeType>(l)) {
1435 if (llvm::isa<SizeType, IndexType>(r))
1439 }
else if (llvm::isa<IndexType>(l)) {
1440 if (llvm::isa<IndexType>(r))
1444 }
else if (llvm::isa<ShapeType>(l)) {
1451 auto rank1 = llvm::cast<RankedTensorType>(l).getShape()[0];
1452 auto rank2 = llvm::cast<RankedTensorType>(r).getShape()[0];
1453 if (ShapedType::isDynamic(rank1))
1455 else if (ShapedType::isDynamic(rank2))
1457 else if (rank1 != rank2)
1463 inferredReturnTypes.assign({
acc});
1468 if (l.size() != 1 || r.size() != 1)
1473 Type lhs = l.front();
1474 Type rhs = r.front();
1476 if (!llvm::isa<ShapeType, SizeType>(lhs))
1477 std::swap(lhs, rhs);
1479 if (llvm::isa<SizeType>(lhs))
1480 return llvm::isa<SizeType, IndexType>(rhs);
1481 if (llvm::isa<ShapeType>(lhs))
1482 return llvm::isa<ShapeType, TensorType>(rhs);
1495 llvm::dyn_cast_if_present<DenseIntElementsAttr>(adaptor.getShape());
1518struct RankShapeOfCanonicalizationPattern
1520 using OpRewritePattern<shape::RankOp>::OpRewritePattern;
1522 LogicalResult matchAndRewrite(shape::RankOp op,
1523 PatternRewriter &rewriter)
const override {
1524 auto shapeOfOp = op.getShape().getDefiningOp<ShapeOfOp>();
1527 auto rankedTensorType =
1528 llvm::dyn_cast<RankedTensorType>(shapeOfOp.getArg().getType());
1529 if (!rankedTensorType)
1531 int64_t rank = rankedTensorType.getRank();
1532 if (llvm::isa<IndexType>(op.getType())) {
1535 }
else if (llvm::isa<shape::SizeType>(op.getType())) {
1547 patterns.
add<RankShapeOfCanonicalizationPattern>(context);
1550LogicalResult mlir::shape::RankOp::inferReturnTypes(
1551 MLIRContext *context, std::optional<Location> location,
1553 if (llvm::isa<ShapeType>(adaptor.getShape().getType()))
1554 inferredReturnTypes.assign({SizeType::get(context)});
1556 inferredReturnTypes.assign({IndexType::get(context)});
1579 for (
auto value : llvm::cast<DenseIntElementsAttr>(
shape))
1585LogicalResult mlir::shape::NumElementsOp::inferReturnTypes(
1586 MLIRContext *context, std::optional<Location> location,
1587 NumElementsOp::Adaptor adaptor,
1589 if (llvm::isa<ShapeType>(adaptor.getShape().getType()))
1590 inferredReturnTypes.assign({SizeType::get(context)});
1592 inferredReturnTypes.assign({IndexType::get(context)});
1596bool mlir::shape::NumElementsOp::isCompatibleReturnTypes(
TypeRange l,
1602LogicalResult shape::NumElementsOp::verify() {
1612 if (getLhs() == getRhs())
1617LogicalResult mlir::shape::MaxOp::inferReturnTypes(
1618 MLIRContext *context, std::optional<Location> location,
1620 if (adaptor.getLhs().getType() == adaptor.getRhs().getType())
1621 inferredReturnTypes.assign({adaptor.getLhs().getType()});
1623 inferredReturnTypes.assign({SizeType::get(context)});
1628 if (l.size() != 1 || r.size() != 1)
1630 if (llvm::isa<ShapeType>(l.front()) && llvm::isa<ShapeType>(r.front()))
1632 if (llvm::isa<SizeType>(l.front()) && llvm::isa<SizeType>(r.front()))
1643 if (getLhs() == getRhs())
1648LogicalResult mlir::shape::MinOp::inferReturnTypes(
1649 MLIRContext *context, std::optional<Location> location,
1651 if (adaptor.getLhs().getType() == adaptor.getRhs().getType())
1652 inferredReturnTypes.assign({adaptor.getLhs().getType()});
1654 inferredReturnTypes.assign({SizeType::get(context)});
1659 if (l.size() != 1 || r.size() != 1)
1661 if (llvm::isa<ShapeType>(l.front()) && llvm::isa<ShapeType>(r.front()))
1663 if (llvm::isa<SizeType>(l.front()) && llvm::isa<SizeType>(r.front()))
1673 auto lhs = llvm::dyn_cast_if_present<IntegerAttr>(adaptor.getLhs());
1676 auto rhs = llvm::dyn_cast_if_present<IntegerAttr>(adaptor.getRhs());
1679 APInt folded = lhs.getValue() * rhs.getValue();
1681 return IntegerAttr::get(indexTy, folded);
1684LogicalResult mlir::shape::MulOp::inferReturnTypes(
1685 MLIRContext *context, std::optional<Location> location,
1687 if (llvm::isa<SizeType>(adaptor.getLhs().getType()) ||
1688 llvm::isa<SizeType>(adaptor.getRhs().getType()))
1689 inferredReturnTypes.assign({SizeType::get(context)});
1691 inferredReturnTypes.assign({IndexType::get(context)});
1708struct ShapeOfOpToConstShapeOp :
public OpRewritePattern<shape::ShapeOfOp> {
1709 using OpRewritePattern<shape::ShapeOfOp>::OpRewritePattern;
1711 LogicalResult matchAndRewrite(shape::ShapeOfOp op,
1712 PatternRewriter &rewriter)
const override {
1713 auto type = llvm::dyn_cast<ShapedType>(op.getArg().getType());
1714 if (!type || !type.hasStaticShape())
1717 Type resultType = op.getResult().getType();
1718 Location loc = op.getLoc();
1720 isa<ShapeType>(resultType)
1722 : RankedTensorType::get({type.getRank()}, rewriter.
getIndexType());
1724 ConstShapeOp::create(rewriter, loc, constResType,
1727 if (constShape.
getType() != resultType)
1729 tensor::CastOp::create(rewriter, loc, resultType, constShape);
1748 using OpRewritePattern<shape::ShapeOfOp>::OpRewritePattern;
1750 LogicalResult matchAndRewrite(shape::ShapeOfOp op,
1751 PatternRewriter &rewriter)
const override {
1752 auto tensorReshapeOp = op.getArg().getDefiningOp<tensor::ReshapeOp>();
1753 if (!tensorReshapeOp)
1755 if (!isa<TensorType>(op.getType()))
1766 Value shape = tensorReshapeOp.getShape();
1768 auto opTensorTy = cast<RankedTensorType>(op.getType());
1769 auto shapeTensorTy = cast<RankedTensorType>(shape.
getType());
1771 if (opTensorTy != shapeTensorTy) {
1772 if (opTensorTy.getElementType() == shapeTensorTy.getElementType())
1774 tensor::CastOp::create(rewriter, op.getLoc(), opTensorTy, shape);
1776 shape = arith::IndexCastOp::create(rewriter, op.getLoc(), opTensorTy,
1795 using OpRewritePattern<tensor::CastOp>::OpRewritePattern;
1797 LogicalResult matchAndRewrite(tensor::CastOp op,
1798 PatternRewriter &rewriter)
const override {
1799 auto ty = llvm::dyn_cast<RankedTensorType>(op.getType());
1800 if (!ty || ty.getRank() != 1)
1803 auto shapeOfOp = op.getSource().getDefiningOp<ShapeOfOp>();
1808 auto argTy = llvm::dyn_cast<RankedTensorType>(shapeOfOp.getArg().getType());
1809 if (!argTy || (!ty.isDynamicDim(0) && ty.getDimSize(0) != argTy.getRank()))
1820 patterns.
add<ShapeOfCastExtentTensor, ShapeOfFromReshape,
1821 ExtractFromShapeOfExtentTensor, ShapeOfOpToConstShapeOp>(
1825LogicalResult mlir::shape::ShapeOfOp::inferReturnTypes(
1826 MLIRContext *context, std::optional<Location> location,
1828 if (llvm::isa<ValueShapeType>(adaptor.getArg().getType()))
1829 inferredReturnTypes.assign({ShapeType::get(context)});
1831 auto shapedTy = llvm::cast<ShapedType>(adaptor.getArg().getType());
1833 shapedTy.hasRank() ? shapedTy.getRank() : ShapedType::kDynamic;
1834 Type indexTy = IndexType::get(context);
1835 Type extentTensorTy = RankedTensorType::get({rank}, indexTy);
1836 inferredReturnTypes.assign({extentTensorTy});
1842 if (l.size() != 1 || r.size() != 1)
1847 Type lhs = l.front();
1848 Type rhs = r.front();
1850 if (!llvm::isa<ShapeType, ShapedType>(lhs) ||
1851 !llvm::isa<ShapeType, ShapedType>(rhs))
1854 if (llvm::isa<ShapeType>(lhs) || llvm::isa<ShapeType>(rhs))
1863LogicalResult shape::ShapeOfOp::verify() {
1881 patterns.
add<IndexToSizeToIndexCanonicalization>(context);
1885 if (inputs.size() != 1 || outputs.size() != 1)
1887 return llvm::isa<IndexType, SizeType>(inputs[0]) &&
1888 llvm::isa<IndexType>(outputs[0]);
1895LogicalResult shape::YieldOp::verify() {
1896 auto *parentOp = (*this)->getParentOp();
1897 auto results = parentOp->getResults();
1898 auto operands = getOperands();
1901 return emitOpError() <<
"number of operands does not match number of "
1902 "results of its parent";
1903 for (
auto e : llvm::zip(results, operands))
1905 return emitOpError() <<
"types mismatch between yield op and its parent";
1914LogicalResult SplitAtOp::fold(FoldAdaptor adaptor,
1916 if (!adaptor.getOperand() || !adaptor.getIndex())
1919 llvm::to_vector<6>(llvm::cast<DenseIntElementsAttr>(adaptor.getOperand())
1922 auto splitPoint = llvm::cast<IntegerAttr>(adaptor.getIndex()).getInt();
1926 if (-rank > splitPoint || splitPoint > rank)
1929 splitPoint +=
shape.size();
1930 Builder builder(adaptor.getOperand().getContext());
1940OpFoldResult ToExtentTensorOp::fold(FoldAdaptor adaptor) {
1941 if (!adaptor.getInput())
1945 llvm::to_vector<6>(llvm::cast<DenseIntElementsAttr>(adaptor.getInput())
1947 auto type = RankedTensorType::get({
static_cast<int64_t>(
shape.size())},
1953 if (inputs.size() != 1 || outputs.size() != 1)
1955 if (
auto inputTensor = llvm::dyn_cast<RankedTensorType>(inputs[0])) {
1956 if (!llvm::isa<IndexType>(inputTensor.getElementType()) ||
1957 inputTensor.getRank() != 1)
1959 }
else if (!llvm::isa<ShapeType>(inputs[0])) {
1963 TensorType outputTensor = llvm::dyn_cast<TensorType>(outputs[0]);
1964 return outputTensor && llvm::isa<IndexType>(outputTensor.
getElementType());
1975 result.addOperands(initVals);
1982 if (
auto tensorType = llvm::dyn_cast<TensorType>(
shape.getType()))
1983 elementType = tensorType.getElementType();
1985 elementType = SizeType::get(builder.
getContext());
1988 for (
Value initVal : initVals) {
1989 bodyBlock->
addArgument(initVal.getType(), initVal.getLoc());
1990 result.addTypes(initVal.getType());
1994LogicalResult ReduceOp::verify() {
1999 auto blockArgsCount = getInitVals().size() + 2;
2001 return emitOpError() <<
"ReduceOp body is expected to have "
2002 << blockArgsCount <<
" arguments";
2007 "argument 0 of ReduceOp body is expected to be of IndexType");
2014 if (!llvm::isa<SizeType>(extentTy))
2015 return emitOpError(
"argument 1 of ReduceOp body is expected to be of "
2016 "SizeType if the ReduceOp operates on a ShapeType");
2018 if (!llvm::isa<IndexType>(extentTy))
2020 "argument 1 of ReduceOp body is expected to be of IndexType if the "
2021 "ReduceOp operates on an extent tensor");
2024 for (
const auto &type : llvm::enumerate(getInitVals()))
2026 return emitOpError() <<
"type mismatch between argument "
2028 <<
" of ReduceOp body and initial value "
2036 Type shapeOrExtentTensorType;
2045 if (parser.
resolveOperand(operands.front(), shapeOrExtentTensorType,
2064 p <<
'(' <<
getShape() <<
", " << getInitVals()
2072#define GET_OP_CLASSES
2073#include "mlir/Dialect/Shape/IR/ShapeOps.cpp.inc"
2075#define GET_TYPEDEF_CLASSES
2076#include "mlir/Dialect/Shape/IR/ShapeOpsTypes.cpp.inc"
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static bool isErrorPropagationPossible(TypeRange operandTypes)
static bool hasAtMostSingleNonScalar(ArrayRef< Attribute > attributes)
static LogicalResult verifyShapeOrExtentTensorOp(Operation *op)
static bool eachHasOnlyOneOfTypes(TypeRange typeRange)
static LogicalResult verifySizeOrIndexOp(Operation *op)
static int64_t product(ArrayRef< int64_t > vals)
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
ParseResult parseSymbolName(StringAttr &result)
Parse an -identifier and store it (without the '@' symbol) in a string attribute.
@ Paren
Parens surrounding zero or more operands.
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 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 SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional arrow followed by a type list.
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.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual void printType(Type type)
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
void printOptionalArrowTypeList(TypeRange &&types)
Print an optional arrow followed by a type list.
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
static BoolAttr get(MLIRContext *context, bool value)
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIndexAttr(int64_t value)
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
StringAttr getStringAttr(const Twine &bytes)
DenseIntElementsAttr getIndexTensorAttr(ArrayRef< int64_t > values)
MLIRContext * getContext() const
An attribute that represents a reference to a dense integer vector or tensor object.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
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.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
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 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.
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::iterator getInsertionPoint() const
Returns the current insertion point of the builder.
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.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
This class represents a single result from folding an operation.
A trait used to provide symbol table functionalities to a region operation.
StringAttr getIdentifier() const
Return the name of this operation as a StringAttr.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
iterator_range< dialect_attr_iterator > dialect_attr_range
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
result_type_range getResultTypes()
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.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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 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.
Block * splitBlock(Block *block, Block::iterator before)
Split the operations starting at "before" (inclusive) out of the given block into a new block,...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void mergeBlocks(Block *source, Block *dest, ValueRange argValues={})
Inline the operations of block 'source' into the end of block 'dest'.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void inlineRegionBefore(Region ®ion, Region &parent, Region::iterator before)
Move the blocks that belong to "region" before the given position in another region "parent".
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Type getElementType() const
Returns the element type of this tensor type.
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...
This class provides an abstraction over the different types of ranges over Values.
ValueTypeRange< ValueRange > type_range
Type front()
Return first type in the range.
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.
A named class for passing around the variadic flag.
bool staticallyKnownBroadcastable(ArrayRef< SmallVector< int64_t, 6 > > shapes)
Returns true if a broadcast between n shapes is guaranteed to be successful and not result in an erro...
bool getBroadcastedShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2, SmallVectorImpl< int64_t > &resultShape)
Returns true and sets resultShape to the broadcasted shape from the two given shapes if they are broa...
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 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.
DynamicAPInt getIndex(const ConeV &cone)
Get the index of a cone, i.e., the volume of the parallelepiped spanned by its generators,...
bool isExtentTensorType(Type)
LogicalResult getShapeVec(Value input, SmallVectorImpl< int64_t > &shapeValues)
RankedTensorType getExtentTensorType(MLIRContext *ctx, int64_t rank=ShapedType::kDynamic)
Alias type for extent tensors.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
LogicalResult verifyCompatibleShapes(TypeRange types1, TypeRange types2)
Returns success if the given two arrays have the same number of elements and each pair wise entries h...
Attribute constFoldBinaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
LogicalResult emitOptionalError(std::optional< Location > loc, Args &&...args)
Overloads of the above emission functions that take an optionally null location.
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
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
llvm::function_ref< Fn > function_ref
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.