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 ®istry) { 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