diff --git a/llvm/include/llvm/ADT/Sequence.h b/llvm/include/llvm/ADT/Sequence.h --- a/llvm/include/llvm/ADT/Sequence.h +++ b/llvm/include/llvm/ADT/Sequence.h @@ -42,6 +42,10 @@ value_sequence_iterator(const value_sequence_iterator &) = default; value_sequence_iterator(value_sequence_iterator &&Arg) : Value(std::move(Arg.Value)) {} + value_sequence_iterator &operator=(const value_sequence_iterator &Arg) { + Value = Arg.Value; + return *this; + } template ()))> value_sequence_iterator(U &&Value) : Value(std::forward(Value)) {} diff --git a/mlir/include/mlir/Pass/AnalysisManager.h b/mlir/include/mlir/Pass/AnalysisManager.h --- a/mlir/include/mlir/Pass/AnalysisManager.h +++ b/mlir/include/mlir/Pass/AnalysisManager.h @@ -286,7 +286,7 @@ return it->second->analyses.getCachedAnalysis(); } - /// Get an analysis manager for the given child operation. + /// Get an analysis manager for the given operation. AnalysisManager nest(Operation *op); /// Invalidate any non preserved analyses, @@ -310,6 +310,9 @@ detail::NestedAnalysisMap *impl) : parent(parent), impl(impl) {} + /// Get an analysis manager for the given immediately nested child operation. + AnalysisManager nestImmediate(Operation *op); + /// A reference to the parent analysis manager, or the top-level module /// analysis manager. ParentPointerT parent; diff --git a/mlir/include/mlir/Pass/Pass.h b/mlir/include/mlir/Pass/Pass.h --- a/mlir/include/mlir/Pass/Pass.h +++ b/mlir/include/mlir/Pass/Pass.h @@ -114,7 +114,10 @@ }; /// Attempt to initialize the options of this pass from the given string. - LogicalResult initializeOptions(StringRef options); + /// Derived classes may override this method to hook into the point at which + /// options are initialized, but should generally always invoke this base + /// class variant. + virtual LogicalResult initializeOptions(StringRef options); /// Prints out the pass in the textual representation of pipelines. If this is /// an adaptor pass, print with the op_name(sub_pass,...) format. diff --git a/mlir/include/mlir/Pass/PassManager.h b/mlir/include/mlir/Pass/PassManager.h --- a/mlir/include/mlir/Pass/PassManager.h +++ b/mlir/include/mlir/Pass/PassManager.h @@ -49,8 +49,8 @@ class OpPassManager { public: enum class Nesting { Implicit, Explicit }; - OpPassManager(Identifier name, Nesting nesting); - OpPassManager(StringRef name, Nesting nesting); + OpPassManager(Identifier name, Nesting nesting = Nesting::Explicit); + OpPassManager(StringRef name, Nesting nesting = Nesting::Explicit); OpPassManager(OpPassManager &&rhs); OpPassManager(const OpPassManager &rhs); ~OpPassManager(); diff --git a/mlir/include/mlir/Transforms/Passes.h b/mlir/include/mlir/Transforms/Passes.h --- a/mlir/include/mlir/Transforms/Passes.h +++ b/mlir/include/mlir/Transforms/Passes.h @@ -99,6 +99,19 @@ /// Creates a pass which inlines calls and callable operations as defined by /// the CallGraph. std::unique_ptr createInlinerPass(); +/// Creates an instance of the inliner pass, and use the provided pass managers +/// when optimizing callable operations with names matching the key type. +/// Callable operations with a name not within the provided map will use the +/// default inliner pipeline during optimization. +std::unique_ptr +createInlinerPass(llvm::StringMap opPipelines); +/// Creates an instance of the inliner pass, and use the provided pass managers +/// when optimizing callable operations with names matching the key type. +/// Callable operations with a name not within the provided map will use the +/// provided default pipeline builder. +std::unique_ptr +createInlinerPass(llvm::StringMap opPipelines, + std::function defaultPipelineBuilder); /// Creates a pass which performs sparse conditional constant propagation over /// nested operations. diff --git a/mlir/include/mlir/Transforms/Passes.td b/mlir/include/mlir/Transforms/Passes.td --- a/mlir/include/mlir/Transforms/Passes.td +++ b/mlir/include/mlir/Transforms/Passes.td @@ -277,9 +277,12 @@ let summary = "Inline function calls"; let constructor = "mlir::createInlinerPass()"; let options = [ - Option<"disableCanonicalization", "disable-simplify", "bool", - /*default=*/"false", - "Disable running simplifications during inlining">, + Option<"defaultPipelineStr", "default-pipeline", "std::string", + /*default=*/"", "The default optimizer pipeline used for callables">, + ListOption<"opPipelineStrs", "op-pipelines", "std::string", + "Callable operation specific optimizer pipelines (in the form " + "of `dialect.op(pipeline)`)", + "llvm::cl::MiscFlags::CommaSeparated">, Option<"maxInliningIterations", "max-iterations", "unsigned", /*default=*/"4", "Maximum number of iterations when inlining within an SCC">, diff --git a/mlir/lib/Pass/Pass.cpp b/mlir/lib/Pass/Pass.cpp --- a/mlir/lib/Pass/Pass.cpp +++ b/mlir/lib/Pass/Pass.cpp @@ -373,7 +373,7 @@ "operation that isn't " "nested under the current operation the pass is processing"; - AnalysisManager nestedAm = am.nest(root); + AnalysisManager nestedAm = root == op ? am : am.nest(root); return OpToOpPassAdaptor::runPipeline(pipeline.getPasses(), root, nestedAm, verifyPasses); }; @@ -870,6 +870,32 @@ /// Get an analysis manager for the given child operation. AnalysisManager AnalysisManager::nest(Operation *op) { + Operation *currentOp = impl->getOperation(); + assert(currentOp->isProperAncestor(op) && + "expected valid descendant operation"); + + // Check for the base case where the provided operation is immediately nested. + if (currentOp == op->getParentOp()) + return nestImmediate(op); + + // Otherwise, we need to collect all ancestors up to the current operation. + SmallVector opAncestors; + do { + opAncestors.push_back(op); + op = op->getParentOp(); + } while (op != currentOp); + + AnalysisManager result = nestImmediate(opAncestors.back()); + for (Operation *op : llvm::drop_begin(llvm::reverse(opAncestors), 1)) + result = result.nestImmediate(op); + return result; +} + +/// Get an analysis manager for the given immediately nested child operation. +AnalysisManager AnalysisManager::nestImmediate(Operation *op) { + assert(impl->getOperation() == op->getParentOp() && + "expected immediate child operation"); + auto it = impl->childAnalyses.find(op); if (it == impl->childAnalyses.end()) it = impl->childAnalyses diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp --- a/mlir/lib/Pass/PassRegistry.cpp +++ b/mlir/lib/Pass/PassRegistry.cpp @@ -281,11 +281,15 @@ /// given to enable accurate error reporting. LogicalResult TextualPipeline::initialize(StringRef text, raw_ostream &errorStream) { + if (text.empty()) + return success(); + // Build a source manager to use for error reporting. llvm::SourceMgr pipelineMgr; - pipelineMgr.AddNewSourceBuffer(llvm::MemoryBuffer::getMemBuffer( - text, "MLIR Textual PassPipeline Parser"), - llvm::SMLoc()); + pipelineMgr.AddNewSourceBuffer( + llvm::MemoryBuffer::getMemBuffer(text, "MLIR Textual PassPipeline Parser", + /*RequiresNullTerminator=*/false), + llvm::SMLoc()); auto errorHandler = [&](const char *rawLoc, Twine msg) { pipelineMgr.PrintMessage(errorStream, llvm::SMLoc::getFromPointer(rawLoc), llvm::SourceMgr::DK_Error, msg); @@ -315,7 +319,7 @@ pipeline.emplace_back(/*name=*/text.substr(0, pos).trim()); // If we have a single terminating name, we're done. - if (pos == text.npos) + if (pos == StringRef::npos) break; text = text.substr(pos); @@ -326,9 +330,19 @@ text = text.substr(1); // Skip over everything until the closing '}' and store as options. - size_t close = text.find('}'); + size_t close = StringRef::npos; + for (unsigned i = 0, e = text.size(), braceCount = 1; i < e; ++i) { + if (text[i] == '{') { + ++braceCount; + continue; + } + if (text[i] == '}' && --braceCount == 0) { + close = i; + break; + } + } - // TODO: Handle skipping over quoted sub-strings. + // Check to see if a closing options brace was found. if (close == StringRef::npos) { return errorHandler( /*rawLoc=*/text.data() - 1, diff --git a/mlir/lib/Transforms/Inliner.cpp b/mlir/lib/Transforms/Inliner.cpp --- a/mlir/lib/Transforms/Inliner.cpp +++ b/mlir/lib/Transforms/Inliner.cpp @@ -15,9 +15,8 @@ #include "PassDetail.h" #include "mlir/Analysis/CallGraph.h" -#include "mlir/IR/PatternMatch.h" #include "mlir/Interfaces/SideEffectInterfaces.h" -#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "mlir/Pass/PassManager.h" #include "mlir/Transforms/InliningUtils.h" #include "mlir/Transforms/Passes.h" #include "llvm/ADT/SCCIterator.h" @@ -28,6 +27,11 @@ using namespace mlir; +/// This function implements the default inliner optimization pipeline. +static void defaultInlinerOptPipeline(OpPassManager &pm) { + pm.addPass(createCanonicalizerPass()); +} + //===----------------------------------------------------------------------===// // Symbol Use Tracking //===----------------------------------------------------------------------===// @@ -279,9 +283,9 @@ /// Run a given transformation over the SCCs of the callgraph in a bottom up /// traversal. -static void -runTransformOnCGSCCs(const CallGraph &cg, - function_ref sccTransformer) { +static LogicalResult runTransformOnCGSCCs( + const CallGraph &cg, + function_ref sccTransformer) { llvm::scc_iterator cgi = llvm::scc_begin(&cg); CallGraphSCC currentSCC(cgi); while (!cgi.isAtEnd()) { @@ -289,8 +293,10 @@ // SCC without invalidating our iterator. currentSCC.reset(*cgi); ++cgi; - sccTransformer(currentSCC); + if (failed(sccTransformer(currentSCC))) + return failure(); } + return success(); } namespace { @@ -499,89 +505,101 @@ return success(inlinedAnyCalls); } -/// Canonicalize the nodes within the given SCC with the given set of -/// canonicalization patterns. -static void canonicalizeSCC(CallGraph &cg, CGUseList &useList, - CallGraphSCC ¤tSCC, MLIRContext *context, - const FrozenRewritePatternList &canonPatterns) { - // Collect the sets of nodes to canonicalize. - SmallVector nodesToCanonicalize; - for (auto *node : currentSCC) { - // Don't canonicalize the external node, it has no valid callable region. - if (node->isExternal()) - continue; - - // Don't canonicalize nodes with children. Nodes with children - // require special handling as we may remove the node during - // canonicalization. In the future, we should be able to handle this - // case with proper node deletion tracking. - if (node->hasChildren()) - continue; - - // We also won't apply canonicalizations for nodes that are not - // isolated. This avoids potentially mutating the regions of nodes defined - // above, this is also a stipulation of the 'applyPatternsAndFoldGreedily' - // driver. - auto *region = node->getCallableRegion(); - if (!region->getParentOp()->isKnownIsolatedFromAbove()) - continue; - nodesToCanonicalize.push_back(node); - } - if (nodesToCanonicalize.empty()) - return; - - // Canonicalize each of the nodes within the SCC in parallel. - // NOTE: This is simple now, because we don't enable canonicalizing nodes - // within children. When we remove this restriction, this logic will need to - // be reworked. - if (context->isMultithreadingEnabled()) { - ParallelDiagnosticHandler canonicalizationHandler(context); - llvm::parallelForEachN( - /*Begin=*/0, /*End=*/nodesToCanonicalize.size(), [&](size_t index) { - // Set the order for this thread so that diagnostics will be properly - // ordered. - canonicalizationHandler.setOrderIDForThread(index); - - // Apply the canonicalization patterns to this region. - auto *node = nodesToCanonicalize[index]; - applyPatternsAndFoldGreedily(*node->getCallableRegion(), - canonPatterns); - - // Make sure to reset the order ID for the diagnostic handler, as this - // thread may be used in a different context. - canonicalizationHandler.eraseOrderIDForThread(); - }); - } else { - for (CallGraphNode *node : nodesToCanonicalize) - applyPatternsAndFoldGreedily(*node->getCallableRegion(), canonPatterns); - } - - // Recompute the uses held by each of the nodes. - for (CallGraphNode *node : nodesToCanonicalize) - useList.recomputeUses(node, cg); -} - //===----------------------------------------------------------------------===// // InlinerPass //===----------------------------------------------------------------------===// namespace { -struct InlinerPass : public InlinerBase { +class InlinerPass : public InlinerBase { +public: + InlinerPass(); + InlinerPass(const InlinerPass &) = default; + InlinerPass(std::function defaultPipeline); + InlinerPass(std::function defaultPipeline, + llvm::StringMap opPipelines); void runOnOperation() override; - /// Attempt to inline calls within the given scc, and run canonicalizations - /// with the given patterns, until a fixed point is reached. This allows for - /// the inlining of newly devirtualized calls. - void inlineSCC(Inliner &inliner, CGUseList &useList, CallGraphSCC ¤tSCC, - MLIRContext *context, - const FrozenRewritePatternList &canonPatterns); +private: + /// Attempt to inline calls within the given scc, and run simplifications, + /// until a fixed point is reached. This allows for the inlining of newly + /// devirtualized calls. Returns failure if there was a fatal error during + /// inlining. + LogicalResult inlineSCC(Inliner &inliner, CGUseList &useList, + CallGraphSCC ¤tSCC, MLIRContext *context); + + /// Optimize the nodes within the given SCC with one of the held optimization + /// pass pipelines. Returns failure if an error occurred during the + /// optimization of the SCC, success otherwise. + LogicalResult optimizeSCC(CallGraph &cg, CGUseList &useList, + CallGraphSCC ¤tSCC, MLIRContext *context); + + /// Optimize the nodes within the given SCC in parallel. Returns failure if an + /// error occurred during the optimization of the SCC, success otherwise. + LogicalResult optimizeSCCAsync(MutableArrayRef nodesToVisit, + MLIRContext *context); + + /// Optimize the given callable node with one of the pass managers provided + /// with `pipelines`, or the default pipeline. Returns failure if an error + /// occurred during the optimization of the callable, success otherwise. + LogicalResult optimizeCallable(CallGraphNode *node, + llvm::StringMap &pipelines); + + /// Attempt to initialize the options of this pass from the given string. + /// Derived classes may override this method to hook into the point at which + /// options are initialized, but should generally always invoke this base + /// class variant. + LogicalResult initializeOptions(StringRef options) override; + + /// An optional function that constructs a default optimization pipeline for + /// a given operation. + std::function defaultPipeline; + /// A map of operation names to pass pipelines to use when optimizing + /// callable operations of these types. This provides a specialized pipeline + /// instead of the default. The vector size is the number of threads used + /// during optimization. + SmallVector, 8> opPipelines; }; } // end anonymous namespace +InlinerPass::InlinerPass() : InlinerPass(defaultInlinerOptPipeline) {} +InlinerPass::InlinerPass(std::function defaultPipeline) + : defaultPipeline(defaultPipeline) { + opPipelines.push_back({}); + + // Initialize the pass options with the provided arguments. + if (defaultPipeline) { + OpPassManager fakePM("__mlir_fake_pm_op"); + defaultPipeline(fakePM); + llvm::raw_string_ostream strStream(defaultPipelineStr); + fakePM.printAsTextualPipeline(strStream); + } +} + +InlinerPass::InlinerPass(std::function defaultPipeline, + llvm::StringMap opPipelines) + : InlinerPass(std::move(defaultPipeline)) { + if (opPipelines.empty()) + return; + + // Update the option for the op specific optimization pipelines. + for (auto &it : opPipelines) { + std::string pipeline; + llvm::raw_string_ostream pipelineOS(pipeline); + pipelineOS << it.getKey() << "("; + it.second.printAsTextualPipeline(pipelineOS); + pipelineOS << ")"; + opPipelineStrs.addValue(pipeline); + } + this->opPipelines.emplace_back(std::move(opPipelines)); +} + void InlinerPass::runOnOperation() { CallGraph &cg = getAnalysis(); auto *context = &getContext(); + printAsTextualPipeline(llvm::errs()); + llvm::errs() << "\n"; + // The inliner should only be run on operations that define a symbol table, // as the callgraph will need to resolve references. Operation *op = getOperation(); @@ -591,42 +609,190 @@ return signalPassFailure(); } - // Collect a set of canonicalization patterns to use when simplifying - // callable regions within an SCC. - OwningRewritePatternList canonPatterns; - for (auto *op : context->getRegisteredOperations()) - op->getCanonicalizationPatterns(canonPatterns, context); - FrozenRewritePatternList frozenCanonPatterns(std::move(canonPatterns)); - // Run the inline transform in post-order over the SCCs in the callgraph. SymbolTableCollection symbolTable; Inliner inliner(context, cg, symbolTable); CGUseList useList(getOperation(), cg, symbolTable); - runTransformOnCGSCCs(cg, [&](CallGraphSCC &scc) { - inlineSCC(inliner, useList, scc, context, frozenCanonPatterns); + LogicalResult result = runTransformOnCGSCCs(cg, [&](CallGraphSCC &scc) { + return inlineSCC(inliner, useList, scc, context); }); + if (failed(result)) + return signalPassFailure(); // After inlining, make sure to erase any callables proven to be dead. inliner.eraseDeadCallables(); } -void InlinerPass::inlineSCC(Inliner &inliner, CGUseList &useList, - CallGraphSCC ¤tSCC, MLIRContext *context, - const FrozenRewritePatternList &canonPatterns) { - // If we successfully inlined any calls, run some simplifications on the - // nodes of the scc. Continue attempting to inline until we reach a fixed - // point, or a maximum iteration count. We canonicalize here as it may - // devirtualize new calls, as well as give us a better cost model. +LogicalResult InlinerPass::inlineSCC(Inliner &inliner, CGUseList &useList, + CallGraphSCC ¤tSCC, + MLIRContext *context) { + // Continuously simplify and inline until we either reach a fixed point, or + // hit the maximum iteration count. Simplifying early helps to refine the cost + // model, and in future iterations may devirtualize new calls. unsigned iterationCount = 0; - while (succeeded(inlineCallsInSCC(inliner, useList, currentSCC))) { - // If we aren't allowing simplifications or the max iteration count was - // reached, then bail out early. - if (disableCanonicalization || ++iterationCount >= maxInliningIterations) + do { + if (failed(optimizeSCC(inliner.cg, useList, currentSCC, context))) + return failure(); + if (failed(inlineCallsInSCC(inliner, useList, currentSCC))) break; - canonicalizeSCC(inliner.cg, useList, currentSCC, context, canonPatterns); + } while (++iterationCount < maxInliningIterations); + return success(); +} + +LogicalResult InlinerPass::optimizeSCC(CallGraph &cg, CGUseList &useList, + CallGraphSCC ¤tSCC, + MLIRContext *context) { + // Collect the sets of nodes to simplify. + SmallVector nodesToVisit; + for (auto *node : currentSCC) { + if (node->isExternal()) + continue; + + // Don't simplify nodes with children. Nodes with children require special + // handling as we may remove the node during simplification. In the future, + // we should be able to handle this case with proper node deletion tracking. + if (node->hasChildren()) + continue; + + // We also won't apply simplifications to nodes that can't have passes + // scheduled on them. + auto *region = node->getCallableRegion(); + if (!region->getParentOp()->isKnownIsolatedFromAbove()) + continue; + nodesToVisit.push_back(node); + } + if (nodesToVisit.empty()) + return success(); + + // Optimize each of the nodes within the SCC in parallel. + // NOTE: This is simple now, because we don't enable optimizing nodes within + // children. When we remove this restriction, this logic will need to be + // reworked. + if (context->isMultithreadingEnabled()) { + if (failed(optimizeSCCAsync(nodesToVisit, context))) + return failure(); + + // Otherwise, we are optimizing within a single thread. + } else { + for (CallGraphNode *node : nodesToVisit) { + if (failed(optimizeCallable(node, opPipelines[0]))) + return failure(); + } + } + + // Recompute the uses held by each of the nodes. + for (CallGraphNode *node : nodesToVisit) + useList.recomputeUses(node, cg); + return success(); +} + +LogicalResult +InlinerPass::optimizeSCCAsync(MutableArrayRef nodesToVisit, + MLIRContext *context) { + // Ensure that there are enough pipeline maps for the optimizer to run in + // parallel. + size_t numThreads = llvm::hardware_concurrency().compute_thread_count(); + if (opPipelines.size() != numThreads) { + // Reserve before resizing so that we can use a reference to the first + // element. + opPipelines.reserve(numThreads); + opPipelines.resize(numThreads, opPipelines.front()); + } + + // Ensure an analysis manager has been constructed for each of the nodes. + // This prevents thread races when running the nested pipelines. + for (CallGraphNode *node : nodesToVisit) + getAnalysisManager().nest(node->getCallableRegion()->getParentOp()); + + // An index for the current node to optimize. + std::atomic nodeIt(0); + + // Optimize the nodes of the SCC in parallel. + ParallelDiagnosticHandler optimizerHandler(context); + return llvm::parallelTransformReduce( + llvm::seq(0, numThreads), success(), + [](LogicalResult lhs, LogicalResult rhs) { + return success(succeeded(lhs) && succeeded(rhs)); + }, + [&](size_t index) { + LogicalResult result = success(); + for (auto e = nodesToVisit.size(); nodeIt < e && succeeded(result);) { + // Get the next available operation index. + unsigned nextID = nodeIt++; + if (nextID >= e) + break; + + // Set the order for this thread so that diagnostics will be + // properly ordered, and reset after optimization has finished. + optimizerHandler.setOrderIDForThread(nextID); + result = optimizeCallable(nodesToVisit[nextID], opPipelines[index]); + optimizerHandler.eraseOrderIDForThread(); + } + return result; + }); +} + +LogicalResult +InlinerPass::optimizeCallable(CallGraphNode *node, + llvm::StringMap &pipelines) { + Operation *callable = node->getCallableRegion()->getParentOp(); + StringRef opName = callable->getName().getStringRef(); + auto pipelineIt = pipelines.find(opName); + if (pipelineIt == pipelines.end()) { + // If a pipeline didn't exist, use the default if possible. + if (!defaultPipeline) + return success(); + + OpPassManager defaultPM(opName); + defaultPipeline(defaultPM); + pipelineIt = pipelines.try_emplace(opName, std::move(defaultPM)).first; } + return runPipeline(pipelineIt->second, callable); +} + +LogicalResult InlinerPass::initializeOptions(StringRef options) { + if (failed(Pass::initializeOptions(options))) + return failure(); + + // Initialize the default pipeline builder to use the option string. + if (!defaultPipelineStr.empty()) { + std::string defaultPipelineCopy = defaultPipelineStr; + defaultPipeline = [=](OpPassManager &pm) { + parsePassPipeline(defaultPipelineCopy, pm); + }; + } else if (defaultPipelineStr.getNumOccurrences()) { + defaultPipeline = nullptr; + } + + // Initialize the op specific pass pipelines. + llvm::StringMap pipelines; + for (StringRef pipeline : opPipelineStrs) { + // Pipelines are expected to be of the form `()`. + size_t pipelineStart = pipeline.find_first_of('('); + if (pipelineStart == StringRef::npos || !pipeline.consume_back(")")) + return failure(); + StringRef opName = pipeline.take_front(pipelineStart); + OpPassManager pm(opName); + if (failed(parsePassPipeline(pipeline.drop_front(1 + pipelineStart), pm))) + return failure(); + pipelines.try_emplace(opName, std::move(pm)); + } + opPipelines.assign({std::move(pipelines)}); + + return success(); } std::unique_ptr mlir::createInlinerPass() { return std::make_unique(); } +std::unique_ptr +mlir::createInlinerPass(llvm::StringMap opPipelines) { + return std::make_unique(defaultInlinerOptPipeline, + std::move(opPipelines)); +} +std::unique_ptr +createInlinerPass(llvm::StringMap opPipelines, + std::function defaultPipelineBuilder) { + return std::make_unique(std::move(defaultPipelineBuilder), + std::move(opPipelines)); +} diff --git a/mlir/test/Dialect/Affine/inlining.mlir b/mlir/test/Dialect/Affine/inlining.mlir --- a/mlir/test/Dialect/Affine/inlining.mlir +++ b/mlir/test/Dialect/Affine/inlining.mlir @@ -1,4 +1,4 @@ -// RUN: mlir-opt -allow-unregistered-dialect %s -inline="disable-simplify" | FileCheck %s +// RUN: mlir-opt -allow-unregistered-dialect %s -inline="default-pipeline=''" | FileCheck %s // Basic test that functions within affine operations are inlined. func @func_with_affine_ops(%N: index) { diff --git a/mlir/test/Dialect/SPIRV/Transforms/inlining.mlir b/mlir/test/Dialect/SPIRV/Transforms/inlining.mlir --- a/mlir/test/Dialect/SPIRV/Transforms/inlining.mlir +++ b/mlir/test/Dialect/SPIRV/Transforms/inlining.mlir @@ -1,4 +1,4 @@ -// RUN: mlir-opt %s -split-input-file -pass-pipeline='spv.module(inline{disable-simplify})' | FileCheck %s +// RUN: mlir-opt %s -split-input-file -pass-pipeline='spv.module(inline{default-pipeline=''})' | FileCheck %s spv.module Logical GLSL450 { spv.func @callee() "None" { diff --git a/mlir/test/Transforms/inlining.mlir b/mlir/test/Transforms/inlining.mlir --- a/mlir/test/Transforms/inlining.mlir +++ b/mlir/test/Transforms/inlining.mlir @@ -1,5 +1,5 @@ -// RUN: mlir-opt %s -inline="disable-simplify" | FileCheck %s -// RUN: mlir-opt %s -inline="disable-simplify" -mlir-print-debuginfo | FileCheck %s --check-prefix INLINE-LOC +// RUN: mlir-opt %s -inline='default-pipeline=''' | FileCheck %s +// RUN: mlir-opt %s -inline='default-pipeline=''' -mlir-print-debuginfo | FileCheck %s --check-prefix INLINE-LOC // RUN: mlir-opt %s -inline | FileCheck %s --check-prefix INLINE_SIMPLIFY // Inline a function that takes an argument.