| //===- TestShapeFunctions.cpp - Passes to test shape function ------------===// | |
| // | |
| // 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 <queue> | |
| #include "mlir/Dialect/Func/IR/FuncOps.h" | |
| #include "mlir/Dialect/Shape/IR/Shape.h" | |
| #include "mlir/IR/BuiltinDialect.h" | |
| #include "mlir/Interfaces/InferTypeOpInterface.h" | |
| #include "mlir/Pass/Pass.h" | |
| using namespace mlir; | |
| namespace { | |
| /// This is a pass that reports shape functions associated with ops. | |
| struct ReportShapeFnPass | |
| : public PassWrapper<ReportShapeFnPass, OperationPass<ModuleOp>> { | |
| MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ReportShapeFnPass) | |
| void runOnOperation() override; | |
| StringRef getArgument() const final { return "test-shape-function-report"; } | |
| StringRef getDescription() const final { | |
| return "Test pass to report associated shape functions"; | |
| } | |
| }; | |
| } // namespace | |
| void ReportShapeFnPass::runOnOperation() { | |
| auto module = getOperation(); | |
| // Report the shape function available to refine the op. | |
| auto shapeFnId = StringAttr::get(&getContext(), "shape.function"); | |
| auto remarkShapeFn = [&](shape::FunctionLibraryOp shapeFnLib, Operation *op) { | |
| if (op->hasTrait<OpTrait::IsTerminator>()) | |
| return true; | |
| if (auto typeInterface = dyn_cast<InferTypeOpInterface>(op)) { | |
| op->emitRemark() << "implements InferType op interface"; | |
| return true; | |
| } | |
| if (auto fn = shapeFnLib.getShapeFunction(op)) { | |
| op->emitRemark() << "associated shape function: " << fn.getName(); | |
| return true; | |
| } | |
| if (auto symbol = op->getAttrOfType<SymbolRefAttr>(shapeFnId)) { | |
| auto fn = | |
| cast<shape::FuncOp>(SymbolTable::lookupSymbolIn(module, symbol)); | |
| op->emitRemark() << "associated shape function: " << fn.getName(); | |
| return true; | |
| } | |
| return false; | |
| }; | |
| // Lookup shape function library. | |
| SmallVector<shape::FunctionLibraryOp, 4> libraries; | |
| auto attr = module->getDiscardableAttr("shape.lib"); | |
| if (attr) { | |
| auto lookup = [&](Attribute attr) { | |
| return cast<shape::FunctionLibraryOp>( | |
| SymbolTable::lookupSymbolIn(module, cast<SymbolRefAttr>(attr))); | |
| }; | |
| if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) { | |
| libraries.reserve(arrayAttr.size()); | |
| for (auto attr : arrayAttr) | |
| libraries.push_back(lookup(attr)); | |
| } else { | |
| libraries.reserve(1); | |
| libraries.push_back(lookup(attr)); | |
| } | |
| } | |
| module.getBodyRegion().walk([&](func::FuncOp func) { | |
| // Skip ops in the shape function library. | |
| if (isa<shape::FunctionLibraryOp>(func->getParentOp())) | |
| return; | |
| func.walk([&](Operation *op) { | |
| bool found = llvm::any_of(libraries, [&](shape::FunctionLibraryOp lib) { | |
| return remarkShapeFn(lib, op); | |
| }); | |
| if (!found) | |
| op->emitRemark() << "no associated way to refine shape"; | |
| }); | |
| }); | |
| } | |
| namespace mlir { | |
| void registerShapeFunctionTestPasses() { | |
| PassRegistration<ReportShapeFnPass>(); | |
| } | |
| } // namespace mlir |