xref: /llvm-project/mlir/examples/transform-opt/mlir-transform-opt.cpp (revision 4f4e2abb1a5ff1225d32410fd02b732d077aa056)
1619ee20bSOleksandr "Alex" Zinenko //===- mlir-transform-opt.cpp -----------------------------------*- C++ -*-===//
2619ee20bSOleksandr "Alex" Zinenko //
3619ee20bSOleksandr "Alex" Zinenko // This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4619ee20bSOleksandr "Alex" Zinenko // See https://llvm.org/LICENSE.txt for license information.
5619ee20bSOleksandr "Alex" Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6619ee20bSOleksandr "Alex" Zinenko //
7619ee20bSOleksandr "Alex" Zinenko //===----------------------------------------------------------------------===//
8619ee20bSOleksandr "Alex" Zinenko 
9619ee20bSOleksandr "Alex" Zinenko #include "mlir/Dialect/Transform/IR/TransformDialect.h"
10619ee20bSOleksandr "Alex" Zinenko #include "mlir/Dialect/Transform/IR/Utils.h"
11619ee20bSOleksandr "Alex" Zinenko #include "mlir/Dialect/Transform/Transforms/TransformInterpreterUtils.h"
12619ee20bSOleksandr "Alex" Zinenko #include "mlir/IR/AsmState.h"
13619ee20bSOleksandr "Alex" Zinenko #include "mlir/IR/BuiltinOps.h"
14619ee20bSOleksandr "Alex" Zinenko #include "mlir/IR/Diagnostics.h"
15619ee20bSOleksandr "Alex" Zinenko #include "mlir/IR/DialectRegistry.h"
16619ee20bSOleksandr "Alex" Zinenko #include "mlir/IR/MLIRContext.h"
17619ee20bSOleksandr "Alex" Zinenko #include "mlir/InitAllDialects.h"
18619ee20bSOleksandr "Alex" Zinenko #include "mlir/InitAllExtensions.h"
19619ee20bSOleksandr "Alex" Zinenko #include "mlir/InitAllPasses.h"
20619ee20bSOleksandr "Alex" Zinenko #include "mlir/Parser/Parser.h"
21619ee20bSOleksandr "Alex" Zinenko #include "mlir/Support/FileUtilities.h"
22619ee20bSOleksandr "Alex" Zinenko #include "mlir/Tools/mlir-opt/MlirOptMain.h"
23619ee20bSOleksandr "Alex" Zinenko #include "llvm/Support/CommandLine.h"
24619ee20bSOleksandr "Alex" Zinenko #include "llvm/Support/InitLLVM.h"
25619ee20bSOleksandr "Alex" Zinenko #include "llvm/Support/SourceMgr.h"
26619ee20bSOleksandr "Alex" Zinenko #include "llvm/Support/ToolOutputFile.h"
27619ee20bSOleksandr "Alex" Zinenko #include <cstdlib>
28619ee20bSOleksandr "Alex" Zinenko 
29619ee20bSOleksandr "Alex" Zinenko namespace {
30619ee20bSOleksandr "Alex" Zinenko 
31619ee20bSOleksandr "Alex" Zinenko using namespace llvm;
32619ee20bSOleksandr "Alex" Zinenko 
33619ee20bSOleksandr "Alex" Zinenko /// Structure containing command line options for the tool, these will get
34619ee20bSOleksandr "Alex" Zinenko /// initialized when an instance is created.
35619ee20bSOleksandr "Alex" Zinenko struct MlirTransformOptCLOptions {
36619ee20bSOleksandr "Alex" Zinenko   cl::opt<bool> allowUnregisteredDialects{
37619ee20bSOleksandr "Alex" Zinenko       "allow-unregistered-dialect",
38619ee20bSOleksandr "Alex" Zinenko       cl::desc("Allow operations coming from an unregistered dialect"),
39619ee20bSOleksandr "Alex" Zinenko       cl::init(false)};
40619ee20bSOleksandr "Alex" Zinenko 
41619ee20bSOleksandr "Alex" Zinenko   cl::opt<bool> verifyDiagnostics{
42619ee20bSOleksandr "Alex" Zinenko       "verify-diagnostics",
43619ee20bSOleksandr "Alex" Zinenko       cl::desc("Check that emitted diagnostics match expected-* lines "
44619ee20bSOleksandr "Alex" Zinenko                "on the corresponding line"),
45619ee20bSOleksandr "Alex" Zinenko       cl::init(false)};
46619ee20bSOleksandr "Alex" Zinenko 
47619ee20bSOleksandr "Alex" Zinenko   cl::opt<std::string> payloadFilename{cl::Positional, cl::desc("<input file>"),
48619ee20bSOleksandr "Alex" Zinenko                                        cl::init("-")};
49619ee20bSOleksandr "Alex" Zinenko 
50619ee20bSOleksandr "Alex" Zinenko   cl::opt<std::string> outputFilename{"o", cl::desc("Output filename"),
51619ee20bSOleksandr "Alex" Zinenko                                       cl::value_desc("filename"),
52619ee20bSOleksandr "Alex" Zinenko                                       cl::init("-")};
53619ee20bSOleksandr "Alex" Zinenko 
54619ee20bSOleksandr "Alex" Zinenko   cl::opt<std::string> transformMainFilename{
55619ee20bSOleksandr "Alex" Zinenko       "transform",
56619ee20bSOleksandr "Alex" Zinenko       cl::desc("File containing entry point of the transform script, if "
57619ee20bSOleksandr "Alex" Zinenko                "different from the input file"),
58619ee20bSOleksandr "Alex" Zinenko       cl::value_desc("filename"), cl::init("")};
59619ee20bSOleksandr "Alex" Zinenko 
60619ee20bSOleksandr "Alex" Zinenko   cl::list<std::string> transformLibraryFilenames{
61619ee20bSOleksandr "Alex" Zinenko       "transform-library", cl::desc("File(s) containing definitions of "
62619ee20bSOleksandr "Alex" Zinenko                                     "additional transform script symbols")};
63619ee20bSOleksandr "Alex" Zinenko 
64619ee20bSOleksandr "Alex" Zinenko   cl::opt<std::string> transformEntryPoint{
65619ee20bSOleksandr "Alex" Zinenko       "transform-entry-point",
66619ee20bSOleksandr "Alex" Zinenko       cl::desc("Name of the entry point transform symbol"),
67619ee20bSOleksandr "Alex" Zinenko       cl::init(mlir::transform::TransformDialect::kTransformEntryPointSymbolName
68619ee20bSOleksandr "Alex" Zinenko                    .str())};
69619ee20bSOleksandr "Alex" Zinenko 
70619ee20bSOleksandr "Alex" Zinenko   cl::opt<bool> disableExpensiveChecks{
71619ee20bSOleksandr "Alex" Zinenko       "disable-expensive-checks",
72619ee20bSOleksandr "Alex" Zinenko       cl::desc("Disables potentially expensive checks in the transform "
73619ee20bSOleksandr "Alex" Zinenko                "interpreter, providing more speed at the expense of "
74619ee20bSOleksandr "Alex" Zinenko                "potential memory problems and silent corruptions"),
75619ee20bSOleksandr "Alex" Zinenko       cl::init(false)};
76619ee20bSOleksandr "Alex" Zinenko 
77619ee20bSOleksandr "Alex" Zinenko   cl::opt<bool> dumpLibraryModule{
78619ee20bSOleksandr "Alex" Zinenko       "dump-library-module",
79619ee20bSOleksandr "Alex" Zinenko       cl::desc("Prints the combined library module before the output"),
80619ee20bSOleksandr "Alex" Zinenko       cl::init(false)};
81619ee20bSOleksandr "Alex" Zinenko };
82619ee20bSOleksandr "Alex" Zinenko } // namespace
83619ee20bSOleksandr "Alex" Zinenko 
84619ee20bSOleksandr "Alex" Zinenko /// "Managed" static instance of the command-line options structure. This makes
85619ee20bSOleksandr "Alex" Zinenko /// them locally-scoped and explicitly initialized/deinitialized. While this is
86619ee20bSOleksandr "Alex" Zinenko /// not strictly necessary in the tool source file that is not being used as a
87619ee20bSOleksandr "Alex" Zinenko /// library (where the options would pollute the global list of options), it is
88619ee20bSOleksandr "Alex" Zinenko /// good practice to follow this.
89619ee20bSOleksandr "Alex" Zinenko static llvm::ManagedStatic<MlirTransformOptCLOptions> clOptions;
90619ee20bSOleksandr "Alex" Zinenko 
91619ee20bSOleksandr "Alex" Zinenko /// Explicitly registers command-line options.
92619ee20bSOleksandr "Alex" Zinenko static void registerCLOptions() { *clOptions; }
93619ee20bSOleksandr "Alex" Zinenko 
94619ee20bSOleksandr "Alex" Zinenko namespace {
95619ee20bSOleksandr "Alex" Zinenko /// A wrapper class for source managers diagnostic. This provides both unique
96619ee20bSOleksandr "Alex" Zinenko /// ownership and virtual function-like overload for a pair of
97619ee20bSOleksandr "Alex" Zinenko /// inheritance-related classes that do not use virtual functions.
98619ee20bSOleksandr "Alex" Zinenko class DiagnosticHandlerWrapper {
99619ee20bSOleksandr "Alex" Zinenko public:
100619ee20bSOleksandr "Alex" Zinenko   /// Kind of the diagnostic handler to use.
101619ee20bSOleksandr "Alex" Zinenko   enum class Kind { EmitDiagnostics, VerifyDiagnostics };
102619ee20bSOleksandr "Alex" Zinenko 
103619ee20bSOleksandr "Alex" Zinenko   /// Constructs the diagnostic handler of the specified kind of the given
104619ee20bSOleksandr "Alex" Zinenko   /// source manager and context.
105619ee20bSOleksandr "Alex" Zinenko   DiagnosticHandlerWrapper(Kind kind, llvm::SourceMgr &mgr,
106619ee20bSOleksandr "Alex" Zinenko                            mlir::MLIRContext *context) {
107619ee20bSOleksandr "Alex" Zinenko     if (kind == Kind::EmitDiagnostics)
108619ee20bSOleksandr "Alex" Zinenko       handler = new mlir::SourceMgrDiagnosticHandler(mgr, context);
109619ee20bSOleksandr "Alex" Zinenko     else
110619ee20bSOleksandr "Alex" Zinenko       handler = new mlir::SourceMgrDiagnosticVerifierHandler(mgr, context);
111619ee20bSOleksandr "Alex" Zinenko   }
112619ee20bSOleksandr "Alex" Zinenko 
113619ee20bSOleksandr "Alex" Zinenko   /// This object is non-copyable but movable.
114619ee20bSOleksandr "Alex" Zinenko   DiagnosticHandlerWrapper(const DiagnosticHandlerWrapper &) = delete;
115619ee20bSOleksandr "Alex" Zinenko   DiagnosticHandlerWrapper(DiagnosticHandlerWrapper &&other) = default;
116619ee20bSOleksandr "Alex" Zinenko   DiagnosticHandlerWrapper &
117619ee20bSOleksandr "Alex" Zinenko   operator=(const DiagnosticHandlerWrapper &) = delete;
118619ee20bSOleksandr "Alex" Zinenko   DiagnosticHandlerWrapper &operator=(DiagnosticHandlerWrapper &&) = default;
119619ee20bSOleksandr "Alex" Zinenko 
120619ee20bSOleksandr "Alex" Zinenko   /// Verifies the captured "expected-*" diagnostics if required.
121db791b27SRamkumar Ramachandra   llvm::LogicalResult verify() const {
122619ee20bSOleksandr "Alex" Zinenko     if (auto *ptr =
123619ee20bSOleksandr "Alex" Zinenko             handler.dyn_cast<mlir::SourceMgrDiagnosticVerifierHandler *>()) {
124619ee20bSOleksandr "Alex" Zinenko       return ptr->verify();
125619ee20bSOleksandr "Alex" Zinenko     }
126619ee20bSOleksandr "Alex" Zinenko     return mlir::success();
127619ee20bSOleksandr "Alex" Zinenko   }
128619ee20bSOleksandr "Alex" Zinenko 
129619ee20bSOleksandr "Alex" Zinenko   /// Destructs the object of the same type as allocated.
130619ee20bSOleksandr "Alex" Zinenko   ~DiagnosticHandlerWrapper() {
131619ee20bSOleksandr "Alex" Zinenko     if (auto *ptr = handler.dyn_cast<mlir::SourceMgrDiagnosticHandler *>()) {
132619ee20bSOleksandr "Alex" Zinenko       delete ptr;
133619ee20bSOleksandr "Alex" Zinenko     } else {
134*4f4e2abbSKazu Hirata       delete cast<mlir::SourceMgrDiagnosticVerifierHandler *>(handler);
135619ee20bSOleksandr "Alex" Zinenko     }
136619ee20bSOleksandr "Alex" Zinenko   }
137619ee20bSOleksandr "Alex" Zinenko 
138619ee20bSOleksandr "Alex" Zinenko private:
139619ee20bSOleksandr "Alex" Zinenko   /// Internal storage is a type-safe union.
140619ee20bSOleksandr "Alex" Zinenko   llvm::PointerUnion<mlir::SourceMgrDiagnosticHandler *,
141619ee20bSOleksandr "Alex" Zinenko                      mlir::SourceMgrDiagnosticVerifierHandler *>
142619ee20bSOleksandr "Alex" Zinenko       handler;
143619ee20bSOleksandr "Alex" Zinenko };
144619ee20bSOleksandr "Alex" Zinenko 
145619ee20bSOleksandr "Alex" Zinenko /// MLIR has deeply rooted expectations that the LLVM source manager contains
146619ee20bSOleksandr "Alex" Zinenko /// exactly one buffer, until at least the lexer level. This class wraps
147619ee20bSOleksandr "Alex" Zinenko /// multiple LLVM source managers each managing a buffer to match MLIR's
148619ee20bSOleksandr "Alex" Zinenko /// expectations while still providing a centralized handling mechanism.
149619ee20bSOleksandr "Alex" Zinenko class TransformSourceMgr {
150619ee20bSOleksandr "Alex" Zinenko public:
151619ee20bSOleksandr "Alex" Zinenko   /// Constructs the source manager indicating whether diagnostic messages will
152619ee20bSOleksandr "Alex" Zinenko   /// be verified later on.
153619ee20bSOleksandr "Alex" Zinenko   explicit TransformSourceMgr(bool verifyDiagnostics)
154619ee20bSOleksandr "Alex" Zinenko       : verifyDiagnostics(verifyDiagnostics) {}
155619ee20bSOleksandr "Alex" Zinenko 
156619ee20bSOleksandr "Alex" Zinenko   /// Deconstructs the source manager. Note that `checkResults` must have been
157619ee20bSOleksandr "Alex" Zinenko   /// called on this instance before deconstructing it.
158619ee20bSOleksandr "Alex" Zinenko   ~TransformSourceMgr() {
159619ee20bSOleksandr "Alex" Zinenko     assert(resultChecked && "must check the result of diagnostic handlers by "
160619ee20bSOleksandr "Alex" Zinenko                             "running TransformSourceMgr::checkResult");
161619ee20bSOleksandr "Alex" Zinenko   }
162619ee20bSOleksandr "Alex" Zinenko 
163619ee20bSOleksandr "Alex" Zinenko   /// Parses the given buffer and creates the top-level operation of the kind
164619ee20bSOleksandr "Alex" Zinenko   /// specified as template argument in the given context. Additional parsing
165619ee20bSOleksandr "Alex" Zinenko   /// options may be provided.
166619ee20bSOleksandr "Alex" Zinenko   template <typename OpTy = mlir::Operation *>
167619ee20bSOleksandr "Alex" Zinenko   mlir::OwningOpRef<OpTy> parseBuffer(std::unique_ptr<MemoryBuffer> buffer,
168619ee20bSOleksandr "Alex" Zinenko                                       mlir::MLIRContext &context,
169619ee20bSOleksandr "Alex" Zinenko                                       const mlir::ParserConfig &config) {
170619ee20bSOleksandr "Alex" Zinenko     // Create a single-buffer LLVM source manager. Note that `unique_ptr` allows
171619ee20bSOleksandr "Alex" Zinenko     // the code below to capture a reference to the source manager in such a way
172619ee20bSOleksandr "Alex" Zinenko     // that it is not invalidated when the vector contents is eventually
173619ee20bSOleksandr "Alex" Zinenko     // reallocated.
174619ee20bSOleksandr "Alex" Zinenko     llvm::SourceMgr &mgr =
175619ee20bSOleksandr "Alex" Zinenko         *sourceMgrs.emplace_back(std::make_unique<llvm::SourceMgr>());
176619ee20bSOleksandr "Alex" Zinenko     mgr.AddNewSourceBuffer(std::move(buffer), llvm::SMLoc());
177619ee20bSOleksandr "Alex" Zinenko 
178619ee20bSOleksandr "Alex" Zinenko     // Choose the type of diagnostic handler depending on whether diagnostic
179619ee20bSOleksandr "Alex" Zinenko     // verification needs to happen and store it.
180619ee20bSOleksandr "Alex" Zinenko     if (verifyDiagnostics) {
181619ee20bSOleksandr "Alex" Zinenko       diagHandlers.emplace_back(
182619ee20bSOleksandr "Alex" Zinenko           DiagnosticHandlerWrapper::Kind::VerifyDiagnostics, mgr, &context);
183619ee20bSOleksandr "Alex" Zinenko     } else {
184619ee20bSOleksandr "Alex" Zinenko       diagHandlers.emplace_back(DiagnosticHandlerWrapper::Kind::EmitDiagnostics,
185619ee20bSOleksandr "Alex" Zinenko                                 mgr, &context);
186619ee20bSOleksandr "Alex" Zinenko     }
187619ee20bSOleksandr "Alex" Zinenko 
188619ee20bSOleksandr "Alex" Zinenko     // Defer to MLIR's parser.
189619ee20bSOleksandr "Alex" Zinenko     return mlir::parseSourceFile<OpTy>(mgr, config);
190619ee20bSOleksandr "Alex" Zinenko   }
191619ee20bSOleksandr "Alex" Zinenko 
192619ee20bSOleksandr "Alex" Zinenko   /// If diagnostic message verification has been requested upon construction of
193619ee20bSOleksandr "Alex" Zinenko   /// this source manager, performs the verification, reports errors and returns
194619ee20bSOleksandr "Alex" Zinenko   /// the result of the verification. Otherwise passes through the given value.
195db791b27SRamkumar Ramachandra   llvm::LogicalResult checkResult(llvm::LogicalResult result) {
196619ee20bSOleksandr "Alex" Zinenko     resultChecked = true;
197619ee20bSOleksandr "Alex" Zinenko     if (!verifyDiagnostics)
198619ee20bSOleksandr "Alex" Zinenko       return result;
199619ee20bSOleksandr "Alex" Zinenko 
200619ee20bSOleksandr "Alex" Zinenko     return mlir::failure(llvm::any_of(diagHandlers, [](const auto &handler) {
201619ee20bSOleksandr "Alex" Zinenko       return mlir::failed(handler.verify());
202619ee20bSOleksandr "Alex" Zinenko     }));
203619ee20bSOleksandr "Alex" Zinenko   }
204619ee20bSOleksandr "Alex" Zinenko 
205619ee20bSOleksandr "Alex" Zinenko private:
206619ee20bSOleksandr "Alex" Zinenko   /// Indicates whether diagnostic message verification is requested.
207619ee20bSOleksandr "Alex" Zinenko   const bool verifyDiagnostics;
208619ee20bSOleksandr "Alex" Zinenko 
209619ee20bSOleksandr "Alex" Zinenko   /// Indicates that diagnostic message verification has taken place, and the
210619ee20bSOleksandr "Alex" Zinenko   /// deconstruction is therefore safe.
211619ee20bSOleksandr "Alex" Zinenko   bool resultChecked = false;
212619ee20bSOleksandr "Alex" Zinenko 
213619ee20bSOleksandr "Alex" Zinenko   /// Storage for per-buffer source managers and diagnostic handlers. These are
214619ee20bSOleksandr "Alex" Zinenko   /// wrapped into unique pointers in order to make it safe to capture
215619ee20bSOleksandr "Alex" Zinenko   /// references to these objects: if the vector is reallocated, the unique
216619ee20bSOleksandr "Alex" Zinenko   /// pointer objects are moved by the pointer addresses won't change. Also, for
217619ee20bSOleksandr "Alex" Zinenko   /// handlers, this allows to store the pointer to the base class.
218619ee20bSOleksandr "Alex" Zinenko   SmallVector<std::unique_ptr<llvm::SourceMgr>> sourceMgrs;
219619ee20bSOleksandr "Alex" Zinenko   SmallVector<DiagnosticHandlerWrapper> diagHandlers;
220619ee20bSOleksandr "Alex" Zinenko };
221619ee20bSOleksandr "Alex" Zinenko } // namespace
222619ee20bSOleksandr "Alex" Zinenko 
223619ee20bSOleksandr "Alex" Zinenko /// Trivial wrapper around `applyTransforms` that doesn't support extra mapping
224619ee20bSOleksandr "Alex" Zinenko /// and doesn't enforce the entry point transform ops being top-level.
225db791b27SRamkumar Ramachandra static llvm::LogicalResult
226619ee20bSOleksandr "Alex" Zinenko applyTransforms(mlir::Operation *payloadRoot,
227619ee20bSOleksandr "Alex" Zinenko                 mlir::transform::TransformOpInterface transformRoot,
228619ee20bSOleksandr "Alex" Zinenko                 const mlir::transform::TransformOptions &options) {
229619ee20bSOleksandr "Alex" Zinenko   return applyTransforms(payloadRoot, transformRoot, {}, options,
230619ee20bSOleksandr "Alex" Zinenko                          /*enforceToplevelTransformOp=*/false);
231619ee20bSOleksandr "Alex" Zinenko }
232619ee20bSOleksandr "Alex" Zinenko 
233619ee20bSOleksandr "Alex" Zinenko /// Applies transforms indicated in the transform dialect script to the input
234619ee20bSOleksandr "Alex" Zinenko /// buffer. The transform script may be embedded in the input buffer or as a
235619ee20bSOleksandr "Alex" Zinenko /// separate buffer. The transform script may have external symbols, the
236619ee20bSOleksandr "Alex" Zinenko /// definitions of which must be provided in transform library buffers. If the
237619ee20bSOleksandr "Alex" Zinenko /// application is successful, prints the transformed input buffer into the
238619ee20bSOleksandr "Alex" Zinenko /// given output stream. Additional configuration options are derived from
239619ee20bSOleksandr "Alex" Zinenko /// command-line options.
240db791b27SRamkumar Ramachandra static llvm::LogicalResult processPayloadBuffer(
241619ee20bSOleksandr "Alex" Zinenko     raw_ostream &os, std::unique_ptr<MemoryBuffer> inputBuffer,
242619ee20bSOleksandr "Alex" Zinenko     std::unique_ptr<llvm::MemoryBuffer> transformBuffer,
243619ee20bSOleksandr "Alex" Zinenko     MutableArrayRef<std::unique_ptr<MemoryBuffer>> transformLibraries,
244619ee20bSOleksandr "Alex" Zinenko     mlir::DialectRegistry &registry) {
245619ee20bSOleksandr "Alex" Zinenko 
246619ee20bSOleksandr "Alex" Zinenko   // Initialize the MLIR context, and various configurations.
247619ee20bSOleksandr "Alex" Zinenko   mlir::MLIRContext context(registry, mlir::MLIRContext::Threading::DISABLED);
248619ee20bSOleksandr "Alex" Zinenko   context.allowUnregisteredDialects(clOptions->allowUnregisteredDialects);
249619ee20bSOleksandr "Alex" Zinenko   mlir::ParserConfig config(&context);
250619ee20bSOleksandr "Alex" Zinenko   TransformSourceMgr sourceMgr(
251619ee20bSOleksandr "Alex" Zinenko       /*verifyDiagnostics=*/clOptions->verifyDiagnostics);
252619ee20bSOleksandr "Alex" Zinenko 
253619ee20bSOleksandr "Alex" Zinenko   // Parse the input buffer that will be used as transform payload.
254619ee20bSOleksandr "Alex" Zinenko   mlir::OwningOpRef<mlir::Operation *> payloadRoot =
255619ee20bSOleksandr "Alex" Zinenko       sourceMgr.parseBuffer(std::move(inputBuffer), context, config);
256619ee20bSOleksandr "Alex" Zinenko   if (!payloadRoot)
257619ee20bSOleksandr "Alex" Zinenko     return sourceMgr.checkResult(mlir::failure());
258619ee20bSOleksandr "Alex" Zinenko 
259619ee20bSOleksandr "Alex" Zinenko   // Identify the module containing the transform script entry point. This may
260619ee20bSOleksandr "Alex" Zinenko   // be the same module as the input or a separate module. In the former case,
261619ee20bSOleksandr "Alex" Zinenko   // make a copy of the module so it can be modified freely. Modification may
262619ee20bSOleksandr "Alex" Zinenko   // happen in the script itself (at which point it could be rewriting itself
263619ee20bSOleksandr "Alex" Zinenko   // during interpretation, leading to tricky memory errors) or by embedding
264619ee20bSOleksandr "Alex" Zinenko   // library modules in the script.
265619ee20bSOleksandr "Alex" Zinenko   mlir::OwningOpRef<mlir::ModuleOp> transformRoot;
266619ee20bSOleksandr "Alex" Zinenko   if (transformBuffer) {
267619ee20bSOleksandr "Alex" Zinenko     transformRoot = sourceMgr.parseBuffer<mlir::ModuleOp>(
268619ee20bSOleksandr "Alex" Zinenko         std::move(transformBuffer), context, config);
269619ee20bSOleksandr "Alex" Zinenko     if (!transformRoot)
270619ee20bSOleksandr "Alex" Zinenko       return sourceMgr.checkResult(mlir::failure());
271619ee20bSOleksandr "Alex" Zinenko   } else {
272619ee20bSOleksandr "Alex" Zinenko     transformRoot = cast<mlir::ModuleOp>(payloadRoot->clone());
273619ee20bSOleksandr "Alex" Zinenko   }
274619ee20bSOleksandr "Alex" Zinenko 
275619ee20bSOleksandr "Alex" Zinenko   // Parse and merge the libraries into the main transform module.
276619ee20bSOleksandr "Alex" Zinenko   for (auto &&transformLibrary : transformLibraries) {
277619ee20bSOleksandr "Alex" Zinenko     mlir::OwningOpRef<mlir::ModuleOp> libraryModule =
278619ee20bSOleksandr "Alex" Zinenko         sourceMgr.parseBuffer<mlir::ModuleOp>(std::move(transformLibrary),
279619ee20bSOleksandr "Alex" Zinenko                                               context, config);
280619ee20bSOleksandr "Alex" Zinenko 
281619ee20bSOleksandr "Alex" Zinenko     if (!libraryModule ||
282619ee20bSOleksandr "Alex" Zinenko         mlir::failed(mlir::transform::detail::mergeSymbolsInto(
283619ee20bSOleksandr "Alex" Zinenko             *transformRoot, std::move(libraryModule))))
284619ee20bSOleksandr "Alex" Zinenko       return sourceMgr.checkResult(mlir::failure());
285619ee20bSOleksandr "Alex" Zinenko   }
286619ee20bSOleksandr "Alex" Zinenko 
287619ee20bSOleksandr "Alex" Zinenko   // If requested, dump the combined transform module.
288619ee20bSOleksandr "Alex" Zinenko   if (clOptions->dumpLibraryModule)
289619ee20bSOleksandr "Alex" Zinenko     transformRoot->dump();
290619ee20bSOleksandr "Alex" Zinenko 
291619ee20bSOleksandr "Alex" Zinenko   // Find the entry point symbol. Even if it had originally been in the payload
292619ee20bSOleksandr "Alex" Zinenko   // module, it was cloned into the transform module so only look there.
293619ee20bSOleksandr "Alex" Zinenko   mlir::transform::TransformOpInterface entryPoint =
294619ee20bSOleksandr "Alex" Zinenko       mlir::transform::detail::findTransformEntryPoint(
295619ee20bSOleksandr "Alex" Zinenko           *transformRoot, mlir::ModuleOp(), clOptions->transformEntryPoint);
296619ee20bSOleksandr "Alex" Zinenko   if (!entryPoint)
297619ee20bSOleksandr "Alex" Zinenko     return sourceMgr.checkResult(mlir::failure());
298619ee20bSOleksandr "Alex" Zinenko 
299619ee20bSOleksandr "Alex" Zinenko   // Apply the requested transformations.
300619ee20bSOleksandr "Alex" Zinenko   mlir::transform::TransformOptions transformOptions;
301619ee20bSOleksandr "Alex" Zinenko   transformOptions.enableExpensiveChecks(!clOptions->disableExpensiveChecks);
302619ee20bSOleksandr "Alex" Zinenko   if (mlir::failed(applyTransforms(*payloadRoot, entryPoint, transformOptions)))
303619ee20bSOleksandr "Alex" Zinenko     return sourceMgr.checkResult(mlir::failure());
304619ee20bSOleksandr "Alex" Zinenko 
305619ee20bSOleksandr "Alex" Zinenko   // Print the transformed result and check the captured diagnostics if
306619ee20bSOleksandr "Alex" Zinenko   // requested.
307619ee20bSOleksandr "Alex" Zinenko   payloadRoot->print(os);
308619ee20bSOleksandr "Alex" Zinenko   return sourceMgr.checkResult(mlir::success());
309619ee20bSOleksandr "Alex" Zinenko }
310619ee20bSOleksandr "Alex" Zinenko 
311619ee20bSOleksandr "Alex" Zinenko /// Tool entry point.
312db791b27SRamkumar Ramachandra static llvm::LogicalResult runMain(int argc, char **argv) {
313619ee20bSOleksandr "Alex" Zinenko   // Register all upstream dialects and extensions. Specific uses are advised
314619ee20bSOleksandr "Alex" Zinenko   // not to register all dialects indiscriminately but rather hand-pick what is
315619ee20bSOleksandr "Alex" Zinenko   // necessary for their use case.
316619ee20bSOleksandr "Alex" Zinenko   mlir::DialectRegistry registry;
317619ee20bSOleksandr "Alex" Zinenko   mlir::registerAllDialects(registry);
318619ee20bSOleksandr "Alex" Zinenko   mlir::registerAllExtensions(registry);
319619ee20bSOleksandr "Alex" Zinenko   mlir::registerAllPasses();
320619ee20bSOleksandr "Alex" Zinenko 
321619ee20bSOleksandr "Alex" Zinenko   // Explicitly register the transform dialect. This is not strictly necessary
322619ee20bSOleksandr "Alex" Zinenko   // since it has been already registered as part of the upstream dialect list,
323619ee20bSOleksandr "Alex" Zinenko   // but useful for example purposes for cases when dialects to register are
324619ee20bSOleksandr "Alex" Zinenko   // hand-picked. The transform dialect must be registered.
325619ee20bSOleksandr "Alex" Zinenko   registry.insert<mlir::transform::TransformDialect>();
326619ee20bSOleksandr "Alex" Zinenko 
327619ee20bSOleksandr "Alex" Zinenko   // Register various command-line options. Note that the LLVM initializer
328619ee20bSOleksandr "Alex" Zinenko   // object is a RAII that ensures correct deconstruction of command-line option
329619ee20bSOleksandr "Alex" Zinenko   // objects inside ManagedStatic.
330619ee20bSOleksandr "Alex" Zinenko   llvm::InitLLVM y(argc, argv);
331619ee20bSOleksandr "Alex" Zinenko   mlir::registerAsmPrinterCLOptions();
332619ee20bSOleksandr "Alex" Zinenko   mlir::registerMLIRContextCLOptions();
333619ee20bSOleksandr "Alex" Zinenko   registerCLOptions();
334619ee20bSOleksandr "Alex" Zinenko   llvm::cl::ParseCommandLineOptions(argc, argv,
335619ee20bSOleksandr "Alex" Zinenko                                     "Minimal Transform dialect driver\n");
336619ee20bSOleksandr "Alex" Zinenko 
337619ee20bSOleksandr "Alex" Zinenko   // Try opening the main input file.
338619ee20bSOleksandr "Alex" Zinenko   std::string errorMessage;
339619ee20bSOleksandr "Alex" Zinenko   std::unique_ptr<llvm::MemoryBuffer> payloadFile =
340619ee20bSOleksandr "Alex" Zinenko       mlir::openInputFile(clOptions->payloadFilename, &errorMessage);
341619ee20bSOleksandr "Alex" Zinenko   if (!payloadFile) {
342619ee20bSOleksandr "Alex" Zinenko     llvm::errs() << errorMessage << "\n";
343619ee20bSOleksandr "Alex" Zinenko     return mlir::failure();
344619ee20bSOleksandr "Alex" Zinenko   }
345619ee20bSOleksandr "Alex" Zinenko 
346619ee20bSOleksandr "Alex" Zinenko   // Try opening the output file.
347619ee20bSOleksandr "Alex" Zinenko   std::unique_ptr<llvm::ToolOutputFile> outputFile =
348619ee20bSOleksandr "Alex" Zinenko       mlir::openOutputFile(clOptions->outputFilename, &errorMessage);
349619ee20bSOleksandr "Alex" Zinenko   if (!outputFile) {
350619ee20bSOleksandr "Alex" Zinenko     llvm::errs() << errorMessage << "\n";
351619ee20bSOleksandr "Alex" Zinenko     return mlir::failure();
352619ee20bSOleksandr "Alex" Zinenko   }
353619ee20bSOleksandr "Alex" Zinenko 
354619ee20bSOleksandr "Alex" Zinenko   // Try opening the main transform file if provided.
355619ee20bSOleksandr "Alex" Zinenko   std::unique_ptr<llvm::MemoryBuffer> transformRootFile;
356619ee20bSOleksandr "Alex" Zinenko   if (!clOptions->transformMainFilename.empty()) {
357619ee20bSOleksandr "Alex" Zinenko     if (clOptions->transformMainFilename == clOptions->payloadFilename) {
358619ee20bSOleksandr "Alex" Zinenko       llvm::errs() << "warning: " << clOptions->payloadFilename
359619ee20bSOleksandr "Alex" Zinenko                    << " is provided as both payload and transform file\n";
360619ee20bSOleksandr "Alex" Zinenko     } else {
361619ee20bSOleksandr "Alex" Zinenko       transformRootFile =
362619ee20bSOleksandr "Alex" Zinenko           mlir::openInputFile(clOptions->transformMainFilename, &errorMessage);
363619ee20bSOleksandr "Alex" Zinenko       if (!transformRootFile) {
364619ee20bSOleksandr "Alex" Zinenko         llvm::errs() << errorMessage << "\n";
365619ee20bSOleksandr "Alex" Zinenko         return mlir::failure();
366619ee20bSOleksandr "Alex" Zinenko       }
367619ee20bSOleksandr "Alex" Zinenko     }
368619ee20bSOleksandr "Alex" Zinenko   }
369619ee20bSOleksandr "Alex" Zinenko 
370619ee20bSOleksandr "Alex" Zinenko   // Try opening transform library files if provided.
371619ee20bSOleksandr "Alex" Zinenko   SmallVector<std::unique_ptr<llvm::MemoryBuffer>> transformLibraries;
372619ee20bSOleksandr "Alex" Zinenko   transformLibraries.reserve(clOptions->transformLibraryFilenames.size());
373619ee20bSOleksandr "Alex" Zinenko   for (llvm::StringRef filename : clOptions->transformLibraryFilenames) {
374619ee20bSOleksandr "Alex" Zinenko     transformLibraries.emplace_back(
375619ee20bSOleksandr "Alex" Zinenko         mlir::openInputFile(filename, &errorMessage));
376619ee20bSOleksandr "Alex" Zinenko     if (!transformLibraries.back()) {
377619ee20bSOleksandr "Alex" Zinenko       llvm::errs() << errorMessage << "\n";
378619ee20bSOleksandr "Alex" Zinenko       return mlir::failure();
379619ee20bSOleksandr "Alex" Zinenko     }
380619ee20bSOleksandr "Alex" Zinenko   }
381619ee20bSOleksandr "Alex" Zinenko 
382619ee20bSOleksandr "Alex" Zinenko   return processPayloadBuffer(outputFile->os(), std::move(payloadFile),
383619ee20bSOleksandr "Alex" Zinenko                               std::move(transformRootFile), transformLibraries,
384619ee20bSOleksandr "Alex" Zinenko                               registry);
385619ee20bSOleksandr "Alex" Zinenko }
386619ee20bSOleksandr "Alex" Zinenko 
387619ee20bSOleksandr "Alex" Zinenko int main(int argc, char **argv) {
388619ee20bSOleksandr "Alex" Zinenko   return mlir::asMainReturnCode(runMain(argc, argv));
389619ee20bSOleksandr "Alex" Zinenko }
390