namespace mlir {
class OpPassManager;
+class ParserConfig;
class Pass;
+class PassManager;
namespace detail {
class PassOptions;
std::unique_ptr<detail::PassPipelineCLParserImpl> impl;
};
+//===----------------------------------------------------------------------===//
+// Pass Reproducer
+//===----------------------------------------------------------------------===//
+
+/// Attach an assembly resource parser that handles MLIR reproducer
+/// configurations. Any found reproducer information will be attached to the
+/// given pass manager, e.g. the reproducer pipeline, verification flags, etc.
+// FIXME: Remove the `enableThreading` flag when possible. Some tools, e.g.
+// mlir-opt, force disable threading during parsing.
+void attachPassReproducerAsmResource(ParserConfig &config, PassManager &pm,
+ bool &enableThreading);
+
} // namespace mlir
#endif // MLIR_PASS_PASSREGISTRY_H_
#include "mlir/IR/Dialect.h"
#include "mlir/IR/SymbolTable.h"
#include "mlir/IR/Verifier.h"
+#include "mlir/Parser/Parser.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/FileUtilities.h"
#include "llvm/ADT/STLExtras.h"
}
descOS << "reproducer generated at `" << stream->description() << "`";
- // Output the current pass manager configuration to the crash stream.
- auto &os = stream->os();
- os << "// configuration: -pass-pipeline='" << pipeline << "'";
- if (disableThreads)
- os << " -mlir-disable-threading";
- if (verifyPasses)
- os << " -verify-each";
- os << '\n';
+ AsmState state(preCrashOperation);
+ state.attachResourcePrinter(
+ "mlir_reproducer", [&](Operation *op, AsmResourceBuilder &builder) {
+ builder.buildString("pipeline", pipeline);
+ builder.buildBool("disable_threading", disableThreads);
+ builder.buildBool("verify_each", verifyPasses);
+ });
// Output the .mlir module.
- preCrashOperation->print(os);
+ preCrashOperation->print(stream->os(), state);
}
void RecoveryReproducerContext::disable() {
addInstrumentation(
std::make_unique<CrashReproducerInstrumentation>(*crashReproGenerator));
}
+
+//===----------------------------------------------------------------------===//
+// Asm Resource
+//===----------------------------------------------------------------------===//
+
+void mlir::attachPassReproducerAsmResource(ParserConfig &config,
+ PassManager &pm,
+ bool &enableThreading) {
+ auto parseFn = [&](AsmParsedResourceEntry &entry) -> LogicalResult {
+ if (entry.getKey() == "pipeline") {
+ FailureOr<std::string> pipeline = entry.parseAsString();
+ if (failed(pipeline))
+ return failure();
+ return parsePassPipeline(*pipeline, pm);
+ }
+ if (entry.getKey() == "disable_threading") {
+ FailureOr<bool> value = entry.parseAsBool();
+
+ // FIXME: We should just update the context directly, but some places
+ // force disable threading during parsing.
+ if (succeeded(value))
+ enableThreading = !(*value);
+ return value;
+ }
+ if (entry.getKey() == "verify_each") {
+ FailureOr<bool> value = entry.parseAsBool();
+ if (succeeded(value))
+ pm.enableVerifier(*value);
+ return value;
+ }
+ return entry.emitError() << "unknown 'mlir_reproducer' resource key '"
+ << entry.getKey() << "'";
+ };
+ config.attachResourceParser("mlir_reproducer", parseFn);
+}
bool wasThreadingEnabled = context->isMultithreadingEnabled();
context->disableMultithreading();
+ // Prepare the pass manager and apply any command line options.
+ PassManager pm(context, OpPassManager::Nesting::Implicit);
+ pm.enableVerifier(verifyPasses);
+ applyPassManagerCLOptions(pm);
+ pm.enableTiming(timing);
+
+ // Prepare the parser config, and attach any useful/necessary resource
+ // handlers.
+ ParserConfig config(context);
+ attachPassReproducerAsmResource(config, pm, wasThreadingEnabled);
+
// Parse the input file and reset the context threading state.
TimingScope parserTiming = timing.nest("Parser");
- OwningOpRef<ModuleOp> module(parseSourceFile<ModuleOp>(sourceMgr, context));
+ OwningOpRef<ModuleOp> module(parseSourceFile<ModuleOp>(sourceMgr, config));
context->enableMultithreading(wasThreadingEnabled);
if (!module)
return failure();
parserTiming.stop();
- // Apply any pass manager command line options.
- PassManager pm(context, OpPassManager::Nesting::Implicit);
- pm.enableVerifier(verifyPasses);
- applyPassManagerCLOptions(pm);
- pm.enableTiming(timing);
-
// Callback to build the pipeline.
if (failed(passManagerSetupFn(pm)))
return failure();
"show-dialects", cl::desc("Print the list of registered dialects"),
cl::init(false));
- static cl::opt<bool> runRepro(
- "run-reproducer",
- cl::desc("Append the command line options of the reproducer"),
- cl::init(false));
-
InitLLVM y(argc, argv);
// Register any command line options.
return failure();
}
- // Parse reproducer options.
- BumpPtrAllocator a;
- StringSaver saver(a);
- if (runRepro) {
- auto pair = file->getBuffer().split('\n');
- if (!pair.first.consume_front("// configuration:")) {
- llvm::errs() << "Failed to find repro configuration, expect file to "
- "begin with '// configuration:'\n";
- return failure();
- }
- // Tokenize & parse the first line.
- SmallVector<const char *, 4> newArgv;
- newArgv.push_back(argv[0]);
- llvm::cl::TokenizeGNUCommandLine(pair.first, saver, newArgv);
- cl::ParseCommandLineOptions(newArgv.size(), &newArgv[0], helpHeader);
- }
-
auto output = openOutputFile(outputFilename, &errorMessage);
if (!output) {
llvm::errs() << errorMessage << "\n";
module @foo {}
}
-// REPRO_LOCAL_DYNAMIC_FAILURE: configuration: -pass-pipeline='builtin.module(test-pass-failure)'
// REPRO_LOCAL_DYNAMIC_FAILURE: module @inner_mod1
// REPRO_LOCAL_DYNAMIC_FAILURE: module @foo {
+
+// REPRO_LOCAL_DYNAMIC_FAILURE: pipeline: "builtin.module(test-pass-failure)"
module @foo {}
}
-// REPRO: configuration: -pass-pipeline='builtin.module(test-module-pass,test-pass-crash)'
-
// REPRO: module @inner_mod1
// REPRO: module @foo {
-
-// REPRO_LOCAL: configuration: -pass-pipeline='builtin.module(test-pass-crash)'
+// REPRO: pipeline: "builtin.module(test-module-pass,test-pass-crash)"
// REPRO_LOCAL: module @inner_mod1
// REPRO_LOCAL: module @foo {
-
-// REPRO_LOCAL_DYNAMIC: configuration: -pass-pipeline='builtin.module(test-pass-crash)'
+// REPRO_LOCAL: pipeline: "builtin.module(test-pass-crash)"
// REPRO_LOCAL_DYNAMIC: module @inner_mod1
// REPRO_LOCAL_DYNAMIC: module @foo {
+// REPRO_LOCAL_DYNAMIC: pipeline: "builtin.module(test-pass-crash)"
-// configuration: -mlir-disable-threading=true -pass-pipeline='func.func(cse,canonicalize)' -mlir-print-ir-before=cse
-
-// Test of the reproducer run option. The first line has to be the
-// configuration (matching what is produced by reproducer).
-
-// RUN: mlir-opt %s -run-reproducer 2>&1 | FileCheck -check-prefix=BEFORE %s
+// RUN: mlir-opt %s -mlir-print-ir-before=cse 2>&1 | FileCheck -check-prefix=BEFORE %s
func.func @foo() {
%0 = arith.constant 0 : i32
return
}
+{-#
+ external_resources: {
+ mlir_reproducer: {
+ pipeline: "func.func(cse,canonicalize)",
+ disable_threading: true
+ }
+ }
+#-}
+
// BEFORE: // -----// IR Dump Before{{.*}}CSE //----- //
// BEFORE-NEXT: func @foo()
// BEFORE: // -----// IR Dump Before{{.*}}CSE //----- //
TestModuleCombinerPass() = default;
TestModuleCombinerPass(const TestModuleCombinerPass &) {}
void runOnOperation() override;
-
-private:
- OwningOpRef<spirv::ModuleOp> combinedModule;
};
} // namespace
<< " -> " << newSymbol << "\n";
};
- combinedModule = spirv::combine(modules, combinedModuleBuilder, listener);
+ OwningOpRef<spirv::ModuleOp> combinedModule =
+ spirv::combine(modules, combinedModuleBuilder, listener);
for (spirv::ModuleOp module : modules)
module.erase();
+ combinedModule.release();
}
namespace mlir {