| //===- Linalg.cpp - C Interface for Linalg dialect ------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "mlir-c/Dialect/Linalg.h" | |
| #include "mlir/CAPI/AffineMap.h" | |
| #include "mlir/CAPI/Registration.h" | |
| #include "mlir/Dialect/Linalg/IR/Linalg.h" | |
| using namespace mlir; | |
| using namespace mlir::linalg; | |
| /// Apply the special region builder for the builtin named Linalg op. | |
| /// Assert that `op` is a builtin named Linalg op. | |
| void mlirLinalgFillBuiltinNamedOpRegion(MlirOperation mlirOp) { | |
| Operation *op = unwrap(mlirOp); | |
| auto linalgOp = cast<LinalgOp>(op); | |
| auto *dialect = static_cast<LinalgDialect *>(linalgOp->getDialect()); | |
| LinalgDialect::RegionBuilderFunType fun = | |
| dialect->getRegionBuilder(op->getName().getStringRef()); | |
| assert(fun && "Expected a builtin named Linalg op."); | |
| assert(op->getNumRegions() == 1 && "Expected Linalg op with 1 region"); | |
| assert(op->getRegion(0).getBlocks().empty() && | |
| "Expected Linalg op with 0 blocks"); | |
| SmallVector<Type, 8> argTypes; | |
| SmallVector<Location, 8> argLocs; | |
| for (OpOperand &opOperand : linalgOp->getOpOperands()) { | |
| argTypes.push_back(getElementTypeOrSelf(opOperand.get().getType())); | |
| argLocs.push_back(opOperand.get().getLoc()); | |
| } | |
| ImplicitLocOpBuilder b(op->getLoc(), op->getContext()); | |
| Region ®ion = op->getRegion(0); | |
| Block *body = b.createBlock(®ion, /*insertPt=*/{}, argTypes, argLocs); | |
| b.setInsertionPointToStart(body); | |
| NamedAttrList attrs; | |
| op->getName().walkInherentAttrs( | |
| op, [&](StringRef name, Attribute &attr) { attrs.append(name, attr); }); | |
| fun(b, *body, attrs, /*emitError=*/{}); | |
| } | |
| MLIR_CAPI_EXPORTED bool mlirLinalgIsAContractionOp(MlirOperation op) { | |
| auto linalgOp = llvm::dyn_cast<mlir::linalg::LinalgOp>(unwrap(op)); | |
| // isaContractionOpInterface handles null linalgOp internally. | |
| return linalg::isaContractionOpInterface(linalgOp); | |
| } | |
| static MlirLinalgContractionDimensions | |
| toContractionDimensions(MLIRContext *ctx, | |
| const linalg::ContractionDimensions &dims) { | |
| auto toAttr = [ctx](ArrayRef<unsigned> vals) -> MlirAttribute { | |
| return wrap(DenseI32ArrayAttr::get(ctx, llvm::to_vector_of<int32_t>(vals))); | |
| }; | |
| return {toAttr(dims.batch), toAttr(dims.m), toAttr(dims.n), toAttr(dims.k)}; | |
| } | |
| MLIR_CAPI_EXPORTED MlirLinalgContractionDimensions | |
| mlirLinalgInferContractionDimensions(MlirOperation op) { | |
| auto linalgOp = dyn_cast<linalg::LinalgOp>(unwrap(op)); | |
| if (!linalgOp) | |
| return {}; | |
| FailureOr<linalg::ContractionDimensions> maybeDims = | |
| linalg::inferContractionDims(linalgOp); | |
| if (failed(maybeDims)) | |
| return {}; | |
| const linalg::ContractionDimensions &contractionDims = *maybeDims; | |
| MLIRContext *ctx = linalgOp.getContext(); | |
| return toContractionDimensions(ctx, contractionDims); | |
| } | |
| MLIR_CAPI_EXPORTED MlirLinalgContractionDimensions | |
| mlirLinalgInferContractionDimensionsFromMaps(const MlirAffineMap *indexingMaps, | |
| size_t numMaps) { | |
| if (!indexingMaps || numMaps != 3) | |
| return {}; | |
| SmallVector<AffineMap, 3> maps; | |
| for (size_t i = 0; i < numMaps; ++i) { | |
| maps.push_back(unwrap(indexingMaps[i])); | |
| } | |
| FailureOr<linalg::ContractionDimensions> maybeDims = | |
| linalg::inferContractionDims(maps); | |
| if (failed(maybeDims)) | |
| return {}; | |
| MLIRContext *ctx = maps[0].getContext(); | |
| return toContractionDimensions(ctx, *maybeDims); | |
| } | |
| MLIR_CAPI_EXPORTED bool mlirLinalgIsAConvolutionOp(MlirOperation op) { | |
| auto linalgOp = llvm::dyn_cast<mlir::linalg::LinalgOp>(unwrap(op)); | |
| if (!linalgOp) | |
| return false; | |
| return linalg::isaConvolutionOpInterface(linalgOp); | |
| } | |
| static MlirLinalgConvolutionDimensions | |
| toConvolutionDimensions(MLIRContext *ctx, | |
| const linalg::ConvolutionDimensions &dims) { | |
| auto toI32Attr = [ctx](ArrayRef<unsigned> vals) -> MlirAttribute { | |
| return wrap(DenseI32ArrayAttr::get(ctx, llvm::to_vector_of<int32_t>(vals))); | |
| }; | |
| auto toI64Attr = [ctx](ArrayRef<int64_t> vals) -> MlirAttribute { | |
| return wrap(DenseI64ArrayAttr::get(ctx, vals)); | |
| }; | |
| return {toI32Attr(dims.batch), toI32Attr(dims.outputImage), | |
| toI32Attr(dims.outputChannel), toI32Attr(dims.filterLoop), | |
| toI32Attr(dims.inputChannel), toI32Attr(dims.depth), | |
| toI64Attr(dims.strides), toI64Attr(dims.dilations)}; | |
| } | |
| MLIR_CAPI_EXPORTED MlirLinalgConvolutionDimensions | |
| mlirLinalgInferConvolutionDimensions(MlirOperation op) { | |
| auto linalgOp = llvm::dyn_cast<mlir::linalg::LinalgOp>(unwrap(op)); | |
| if (!linalgOp) | |
| return {}; | |
| FailureOr<linalg::ConvolutionDimensions> maybeDims = | |
| linalg::inferConvolutionDims(linalgOp); | |
| if (failed(maybeDims)) | |
| return {}; | |
| return toConvolutionDimensions(linalgOp.getContext(), *maybeDims); | |
| } | |
| MLIR_CAPI_EXPORTED MlirLinalgConvolutionDimensions | |
| mlirLinalgInferConvolutionDimensionsFromMaps(const MlirAffineMap *indexingMaps, | |
| size_t numMaps) { | |
| // inferConvolutionDims requires exactly 3 maps (input, filter, output); | |
| // keep this check in sync with its contract | |
| if (!indexingMaps || numMaps != 3) | |
| return {}; | |
| SmallVector<AffineMap, 3> maps; | |
| for (size_t i = 0; i < numMaps; ++i) | |
| maps.push_back(unwrap(indexingMaps[i])); | |
| FailureOr<linalg::ConvolutionDimensions> maybeDims = | |
| linalg::inferConvolutionDims(maps); | |
| if (failed(maybeDims)) | |
| return {}; | |
| return toConvolutionDimensions(maps[0].getContext(), *maybeDims); | |
| } | |
| MLIR_CAPI_EXPORTED MlirAttribute | |
| mlirLinalgGetIndexingMapsAttribute(MlirOperation op) { | |
| auto linalgOp = llvm::dyn_cast<mlir::linalg::LinalgOp>(unwrap(op)); | |
| if (!linalgOp) | |
| return MlirAttribute{nullptr}; | |
| ArrayAttr attr = linalgOp.getIndexingMaps(); | |
| return wrap(attr); | |
| } | |
| MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Linalg, linalg, LinalgDialect) |