[Mlir-commits] [mlir] [mlir] add an example of using transform dialect standalone (PR #82623)
Martin Paul Lücke
llvmlistbot at llvm.org
Tue Feb 27 06:59:36 PST 2024
================
@@ -0,0 +1,342 @@
+//===- mlir-transform-opt.cpp -----------------------------------*- C++ -*-===//
+//
+// This file is licensed 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/Dialect/Transform/IR/TransformDialect.h"
+#include "mlir/Dialect/Transform/IR/Utils.h"
+#include "mlir/Dialect/Transform/Transforms/TransformInterpreterUtils.h"
+#include "mlir/IR/AsmState.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/DialectRegistry.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/InitAllDialects.h"
+#include "mlir/InitAllExtensions.h"
+#include "mlir/InitAllPasses.h"
+#include "mlir/Parser/Parser.h"
+#include "mlir/Support/FileUtilities.h"
+#include "mlir/Tools/mlir-opt/MlirOptMain.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <cstdlib>
+
+namespace {
+
+using namespace llvm;
+
+/// Structure containing command line options for the tool, these will get
+/// initialized when an instance is created.
+struct MlirTransformOptCLOptions {
+ cl::opt<bool> allowUnregisteredDialects{
+ "allow-unregistered-dialect",
+ cl::desc("Allow operations coming from an unregistered dialect"),
+ cl::init(false)};
+
+ cl::opt<bool> verifyDiagnostics{
+ "verify-diagnostics",
+ cl::desc("Check that emitted diagnostics match expected-* lines "
+ "on the corresponding line"),
+ cl::init(false)};
+
+ cl::opt<std::string> payloadFilename{cl::Positional, cl::desc("<input file>"),
+ cl::init("-")};
+
+ cl::opt<std::string> outputFilename{"o", cl::desc("Output filename"),
+ cl::value_desc("filename"),
+ cl::init("-")};
+
+ cl::opt<std::string> transformMainFilename{
+ "transform",
+ cl::desc("File containing entry point of the transform script, if "
+ "different from the input file"),
+ cl::value_desc("filename"), cl::init("")};
+
+ cl::list<std::string> transformLibraryFilenames{
+ "transform-library", cl::desc("File(s) containing definitions of "
+ "additional transform script symbols")};
+
+ cl::opt<std::string> transformEntryPoint{
+ "transform-entry-point",
+ cl::desc("Name of the entry point transform symbol"),
+ cl::init(mlir::transform::TransformDialect::kTransformEntryPointSymbolName
+ .str())};
+
+ cl::opt<bool> disableExpensiveChecks{
+ "disable-expensive-checks",
+ cl::desc("Disables potentially expensive checks in the transform "
+ "interpreter, providing more speed at the expense of "
+ "potential memory problems and silent corruptions"),
+ cl::init(false)};
+
+ cl::opt<bool> dumpLibraryModule{
+ "dump-library-module",
+ cl::desc("Prints the combined library module before the output"),
+ cl::init(false)};
+};
+} // namespace
+
+/// "Managed" static instance of the command-line options structure. This makes
+/// them locally-scoped and explicitly initialized/deinitialized. While this is
+/// not strictly necessary in the tool source file that is not being used as a
+/// library (where the options would pollute the global list of options), it is
+/// good practice to follow this.
+static llvm::ManagedStatic<MlirTransformOptCLOptions> clOptions;
+
+/// Explicitly registers command-line options.
+static void registerCLOptions() { *clOptions; }
+
+namespace {
+/// MLIR has deeply rooted expectations that the LLVM source manager contains
+/// exactly one buffer, until at least the lexer level. This class wraps
+/// multiple LLVM source managers each managing a buffer to match MLIR's
+/// expectations while still providing a centralized handling mechanism.
+class TransformSourceMgr {
+public:
+ /// Constructs the source manager indicating whether diagnostic messages will
+ /// be verified later on.
+ explicit TransformSourceMgr(bool verifyDiagnostics)
+ : verifyDiagnostics(verifyDiagnostics) {}
+
+ /// Deconstructs the source manager. Note that `checkResults` must have been
+ /// called on this instance before deconstructing it.
+ ~TransformSourceMgr() {
+ assert(resultChecked && "must check the result of diagnostic handlers by "
+ "running TransformSourceMgr::checkResult");
+ }
+
+ /// Parses the given buffer and creates the top-level operation of the kind
+ /// specified as template argument in the given context. Additional parsing
+ /// options may be provided.
+ template <typename OpTy = mlir::Operation *>
+ mlir::OwningOpRef<OpTy> parseBuffer(std::unique_ptr<MemoryBuffer> buffer,
+ mlir::MLIRContext &context,
+ const mlir::ParserConfig &config) {
+ // Create a single-buffer LLVM source manager. Note that `unique_ptr` allows
+ // the code below to capture a reference to the source manager in such a way
+ // that it is not invalidated when the vector contents is eventually
+ // reallocated.
+ llvm::SourceMgr &mgr =
+ *sourceMgrs.emplace_back(std::make_unique<llvm::SourceMgr>());
+ mgr.AddNewSourceBuffer(std::move(buffer), llvm::SMLoc());
+
+ // Choose the type of diagnostic handler depending on whether diagnostic
+ // verification needs to happen and store it.
+ if (verifyDiagnostics) {
+ diagHandlers.push_back(
+ std::make_unique<mlir::SourceMgrDiagnosticVerifierHandler>(mgr,
+ &context));
+ } else {
+ diagHandlers.push_back(
+ std::make_unique<mlir::SourceMgrDiagnosticHandler>(mgr, &context));
+ }
+
+ // Defer to MLIR's parser.
+ return mlir::parseSourceFile<OpTy>(mgr, config);
+ }
+
+ /// If diagnostic message verification has been requested upon construction of
+ /// this source manager, performs the verification, reports errors and returns
+ /// the result of the verification. Otherwise passes through the given value.
+ mlir::LogicalResult checkResult(mlir::LogicalResult result) {
+ resultChecked = true;
+ if (!verifyDiagnostics)
+ return result;
+
+ return mlir::failure(llvm::any_of(diagHandlers, [](const auto &handler) {
+ return mlir::failed(
+ static_cast<mlir::SourceMgrDiagnosticVerifierHandler *>(handler.get())
+ ->verify());
+ }));
+ }
+
+private:
+ /// Indicates whether diagnostic message verification is requested.
+ const bool verifyDiagnostics;
+
+ /// Indicates that diagnostic message verification has taken place, and the
+ /// deconstruction is therefore safe.
+ bool resultChecked = false;
+
+ /// Storage for per-buffer source managers and diagnostic handlers. These are
+ /// wrapped into unique pointers in order to make it safe to capture
+ /// references to these objects: if the vector is reallocated, the unique
+ /// pointer objects are moved by the pointer addresses won't change. Also, for
+ /// handlers, this allows to store the pointer to the base class.
+ SmallVector<std::unique_ptr<llvm::SourceMgr>> sourceMgrs;
+ SmallVector<std::unique_ptr<mlir::SourceMgrDiagnosticHandler>> diagHandlers;
+};
+} // namespace
+
+/// Trivial wrapper around `applyTransforms` that doesn't support extra mapping
+/// and doesn't enforce the entry point transform ops being top-level.
+static mlir::LogicalResult
+applyTransforms(mlir::Operation *payloadRoot,
+ mlir::transform::TransformOpInterface transformRoot,
+ const mlir::transform::TransformOptions &options) {
+ return applyTransforms(payloadRoot, transformRoot, {}, options,
+ /*enforceToplevelTransformOp=*/false);
+}
+
+/// Applies transforms indicated in the transform dialect script to the input
+/// buffer. The transforms script may be embedded in the input buffer or as a
----------------
martin-luecke wrote:
```suggestion
/// buffer. The transform script may be embedded in the input buffer or as a
```
https://github.com/llvm/llvm-project/pull/82623
More information about the Mlir-commits
mailing list