llvm-project/mlir/unittests/Pass/PassManagerTest.cpp
River Riddle 3655069234 [mlir] Move the Builtin FuncOp to the Func dialect
This commit moves FuncOp out of the builtin dialect, and into the Func
dialect. This move has been planned in some capacity from the moment
we made FuncOp an operation (years ago). This commit handles the
functional aspects of the move, but various aspects are left untouched
to ease migration: func::FuncOp is re-exported into mlir to reduce
the actual API churn, the assembly format still accepts the unqualified
`func`. These temporary measures will remain for a little while to
simplify migration before being removed.

Differential Revision: https://reviews.llvm.org/D121266
2022-03-16 17:07:03 -07:00

137 lines
4.4 KiB
C++

//===- PassManagerTest.cpp - PassManager unit tests -----------------------===//
//
// 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/Pass/PassManager.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
#include "gtest/gtest.h"
#include <memory>
using namespace mlir;
using namespace mlir::detail;
namespace {
/// Analysis that operates on any operation.
struct GenericAnalysis {
GenericAnalysis(Operation *op) : isFunc(isa<FuncOp>(op)) {}
const bool isFunc;
};
/// Analysis that operates on a specific operation.
struct OpSpecificAnalysis {
OpSpecificAnalysis(FuncOp op) : isSecret(op.getName() == "secret") {}
const bool isSecret;
};
/// Simple pass to annotate a FuncOp with the results of analysis.
struct AnnotateFunctionPass
: public PassWrapper<AnnotateFunctionPass, OperationPass<FuncOp>> {
void runOnOperation() override {
FuncOp op = getOperation();
Builder builder(op->getParentOfType<ModuleOp>());
auto &ga = getAnalysis<GenericAnalysis>();
auto &sa = getAnalysis<OpSpecificAnalysis>();
op->setAttr("isFunc", builder.getBoolAttr(ga.isFunc));
op->setAttr("isSecret", builder.getBoolAttr(sa.isSecret));
}
};
TEST(PassManagerTest, OpSpecificAnalysis) {
MLIRContext context;
context.loadDialect<func::FuncDialect>();
Builder builder(&context);
// Create a module with 2 functions.
OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context)));
for (StringRef name : {"secret", "not_secret"}) {
FuncOp func =
FuncOp::create(builder.getUnknownLoc(), name,
builder.getFunctionType(llvm::None, llvm::None));
func.setPrivate();
module->push_back(func);
}
// Instantiate and run our pass.
PassManager pm(&context);
pm.addNestedPass<FuncOp>(std::make_unique<AnnotateFunctionPass>());
LogicalResult result = pm.run(module.get());
EXPECT_TRUE(succeeded(result));
// Verify that each function got annotated with expected attributes.
for (FuncOp func : module->getOps<FuncOp>()) {
ASSERT_TRUE(func->getAttr("isFunc").isa<BoolAttr>());
EXPECT_TRUE(func->getAttr("isFunc").cast<BoolAttr>().getValue());
bool isSecret = func.getName() == "secret";
ASSERT_TRUE(func->getAttr("isSecret").isa<BoolAttr>());
EXPECT_EQ(func->getAttr("isSecret").cast<BoolAttr>().getValue(), isSecret);
}
}
namespace {
struct InvalidPass : Pass {
InvalidPass() : Pass(TypeID::get<InvalidPass>(), StringRef("invalid_op")) {}
StringRef getName() const override { return "Invalid Pass"; }
void runOnOperation() override {}
bool canScheduleOn(RegisteredOperationName opName) const override {
return true;
}
/// A clone method to create a copy of this pass.
std::unique_ptr<Pass> clonePass() const override {
return std::make_unique<InvalidPass>(
*static_cast<const InvalidPass *>(this));
}
};
} // namespace
TEST(PassManagerTest, InvalidPass) {
MLIRContext context;
context.allowUnregisteredDialects();
// Create a module
OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context)));
// Add a single "invalid_op" operation
OpBuilder builder(&module->getBodyRegion());
OperationState state(UnknownLoc::get(&context), "invalid_op");
builder.insert(Operation::create(state));
// Register a diagnostic handler to capture the diagnostic so that we can
// check it later.
std::unique_ptr<Diagnostic> diagnostic;
context.getDiagEngine().registerHandler([&](Diagnostic &diag) {
diagnostic = std::make_unique<Diagnostic>(std::move(diag));
});
// Instantiate and run our pass.
PassManager pm(&context);
pm.nest("invalid_op").addPass(std::make_unique<InvalidPass>());
LogicalResult result = pm.run(module.get());
EXPECT_TRUE(failed(result));
ASSERT_TRUE(diagnostic.get() != nullptr);
EXPECT_EQ(
diagnostic->str(),
"'invalid_op' op trying to schedule a pass on an unregistered operation");
// Check that clearing the pass manager effectively removed the pass.
pm.clear();
result = pm.run(module.get());
EXPECT_TRUE(succeeded(result));
// Check that adding the pass at the top-level triggers a fatal error.
ASSERT_DEATH(pm.addPass(std::make_unique<InvalidPass>()), "");
}
} // namespace