From d82720fe4f511033b17c836ed54bac18818cbe1e Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Thu, 7 Aug 2025 15:31:04 +0000 Subject: [PATCH 1/9] [mlir][spirv] Enable serializer to write SPIR-V modules into separate files By default, `mlir-translate` writes all output into a single file even when `--split-input-file` is used. This is not an issue for text files as they can be easily split with an output separator. However, this causes issues with binary SPIR-V modules. Firstly, a binary file with multiple modules is not a valid SPIR-V, but will be created if multiple modules are specified in the same file and separated by "// -----". This does not cause issues with MLIR internal tools but does not work with SPIRV-Tools. Secondly, splitting binary files after serialization is non-trivial, when compared to text files, so using an external tool is not desirable. This patch adds a SPIR-V serialization option that write SPIR-V modules to separate files in addition to writing them to the `mlir-translate` output file. This is not the ideal solution and ideally `mlir-translate` would allow generating multiple output files when `--split-input-file` is used, however adding such functionality is again non-trival due to how processing and splitting is done: function handles writing to a single `os` that are passed around, and number of split buffers is not known ahead of time. As such a I propose to have a SPIR-V internal option that will dump modules to files in the form they can be processed by `spirv-val`. The behaviour of the new added argument may be confusing, but benefits from being internal to SPIR-V target. Alternatively, we could expose the spirv option in `mlir/lib/Tools/mlir-translate/MlirTranslateMain.cpp`, and slice the output file on the SPIR-V magic number, and not keep the file generated by default by `mlir-translate`. This would be a bit cleaner in API sense, as it would not generate the additional file containing all modules together. However, it pushes SPIR-V specific code into the generic part of the `mlir-translate` and slicing is potentially more error prone that just writing a single module after it was serialized. --- .../include/mlir/Target/SPIRV/Serialization.h | 8 ++++ .../Target/SPIRV/TranslateRegistration.cpp | 44 ++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/mlir/include/mlir/Target/SPIRV/Serialization.h b/mlir/include/mlir/Target/SPIRV/Serialization.h index 225777e25d607..feb80b7d0970e 100644 --- a/mlir/include/mlir/Target/SPIRV/Serialization.h +++ b/mlir/include/mlir/Target/SPIRV/Serialization.h @@ -27,6 +27,14 @@ struct SerializationOptions { bool emitSymbolName = true; /// Whether to emit `OpLine` location information for SPIR-V ops. bool emitDebugInfo = false; + /// Whether to store a module to an additional file during + /// serialization. This is used to store the SPIR-V module to the + /// file in addition to writing it to `os` passed from the calling + /// tool. This saved file is later used for validation. + bool saveModuleForValidation = false; + /// A prefix prepended to the file used when `saveModuleForValidation` + /// is set to `true`. + std::string validationFilePrefix = ""; }; /// Serializes the given SPIR-V `module` and writes to `binary`. On failure, diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index ac338d555e320..5272c63db6831 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/ToolOutputFile.h" using namespace mlir; @@ -76,24 +77,57 @@ void registerFromSPIRVTranslation() { // Serialization registration //===----------------------------------------------------------------------===// -static LogicalResult serializeModule(spirv::ModuleOp module, - raw_ostream &output) { +// Static variable is probably not ideal, but it lets us have unique files names +// without taking additional parameters from `mlir-translate`. +static size_t validationFileCounter = 0; + +static LogicalResult +serializeModule(spirv::ModuleOp module, raw_ostream &output, + const spirv::SerializationOptions &options) { + SmallVector binary; if (failed(spirv::serialize(module, binary))) return failure(); - output.write(reinterpret_cast(binary.data()), - binary.size() * sizeof(uint32_t)); + size_t sizeInBytes = binary.size() * sizeof(uint32_t); + + output.write(reinterpret_cast(binary.data()), sizeInBytes); + + if (options.saveModuleForValidation) { + std::string errorMessage; + std::string filename = + options.validationFilePrefix + std::to_string(validationFileCounter++); + auto validationOutput = openOutputFile(filename, &errorMessage); + if (!validationOutput) { + llvm::errs() << errorMessage << "\n"; + return failure(); + } + validationOutput->os().write(reinterpret_cast(binary.data()), + sizeInBytes); + validationOutput->keep(); + } return mlir::success(); } namespace mlir { void registerToSPIRVTranslation() { + static llvm::cl::opt validationFilesPrefix( + "spirv-save-validation-files-with-prefix", + llvm::cl::desc( + "When non-empty string is passed each serialized SPIR-V module is " + "saved to an additional file that starts with the given prefix. This " + "is used to generate separate binaries for validation, where " + "`--split-input-file` normally combines all outputs into one. The " + "one combined output (`-o`) is still written."), + llvm::cl::init("")); + TranslateFromMLIRRegistration toBinary( "serialize-spirv", "serialize SPIR-V dialect", [](spirv::ModuleOp module, raw_ostream &output) { - return serializeModule(module, output); + return serializeModule(module, output, + {true, false, (validationFilesPrefix != ""), + validationFilesPrefix}); }, [](DialectRegistry ®istry) { registry.insert(); From cbfbd1b030277c716d958898ffd750608c02e9e2 Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Fri, 8 Aug 2025 09:49:15 +0000 Subject: [PATCH 2/9] missing header for mlir-capi-execution-engine-test --- mlir/include/mlir/Target/SPIRV/Serialization.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mlir/include/mlir/Target/SPIRV/Serialization.h b/mlir/include/mlir/Target/SPIRV/Serialization.h index feb80b7d0970e..e5d6859564d1e 100644 --- a/mlir/include/mlir/Target/SPIRV/Serialization.h +++ b/mlir/include/mlir/Target/SPIRV/Serialization.h @@ -15,6 +15,7 @@ #include "mlir/Support/LLVM.h" #include +#include namespace mlir { class MLIRContext; From c2bda5a3bd2175033e7279d1fc228e7999895932 Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Fri, 8 Aug 2025 14:45:55 +0000 Subject: [PATCH 3/9] Check if prefix dir exists --- mlir/lib/Target/SPIRV/TranslateRegistration.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index 5272c63db6831..ac3ebfdeb23e9 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -21,7 +21,9 @@ #include "mlir/Target/SPIRV/Serialization.h" #include "mlir/Tools/mlir-translate/Translation.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" @@ -94,6 +96,17 @@ serializeModule(spirv::ModuleOp module, raw_ostream &output, output.write(reinterpret_cast(binary.data()), sizeInBytes); if (options.saveModuleForValidation) { + size_t dirSeparator = + options.validationFilePrefix.find(llvm::sys::path::get_separator()); + // If file prefix includes directory check if that directory exists. + if (dirSeparator != std::string::npos) { + llvm::StringRef parentDir = + llvm::sys::path::parent_path(options.validationFilePrefix); + if (!llvm::sys::fs::is_directory(parentDir)) { + llvm::errs() << "validation prefix directory does not exist\n"; + return failure(); + } + } std::string errorMessage; std::string filename = options.validationFilePrefix + std::to_string(validationFileCounter++); From 625308de3fa9180763ed8d470b89cbbe9970fa28 Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 10:20:24 +0000 Subject: [PATCH 4/9] Address minor comments --- mlir/include/mlir/Target/SPIRV/Serialization.h | 6 +++--- .../lib/Target/SPIRV/TranslateRegistration.cpp | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mlir/include/mlir/Target/SPIRV/Serialization.h b/mlir/include/mlir/Target/SPIRV/Serialization.h index e5d6859564d1e..67de6ccef487b 100644 --- a/mlir/include/mlir/Target/SPIRV/Serialization.h +++ b/mlir/include/mlir/Target/SPIRV/Serialization.h @@ -38,10 +38,10 @@ struct SerializationOptions { std::string validationFilePrefix = ""; }; -/// Serializes the given SPIR-V `module` and writes to `binary`. On failure, +/// Serializes the given SPIR-V `moduleOp` and writes to `binary`. On failure, /// reports errors to the error handler registered with the MLIR context for -/// `module`. -LogicalResult serialize(ModuleOp module, SmallVectorImpl &binary, +/// `moduleOp`. +LogicalResult serialize(ModuleOp moduleOp, SmallVectorImpl &binary, const SerializationOptions &options = {}); } // namespace spirv diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index ac3ebfdeb23e9..8877461867bb3 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -84,11 +84,10 @@ void registerFromSPIRVTranslation() { static size_t validationFileCounter = 0; static LogicalResult -serializeModule(spirv::ModuleOp module, raw_ostream &output, +serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, const spirv::SerializationOptions &options) { - SmallVector binary; - if (failed(spirv::serialize(module, binary))) + if (failed(spirv::serialize(moduleOp, binary))) return failure(); size_t sizeInBytes = binary.size() * sizeof(uint32_t); @@ -110,7 +109,8 @@ serializeModule(spirv::ModuleOp module, raw_ostream &output, std::string errorMessage; std::string filename = options.validationFilePrefix + std::to_string(validationFileCounter++); - auto validationOutput = openOutputFile(filename, &errorMessage); + std::unique_ptr validationOutput = + openOutputFile(filename, &errorMessage); if (!validationOutput) { llvm::errs() << errorMessage << "\n"; return failure(); @@ -132,14 +132,16 @@ void registerToSPIRVTranslation() { "saved to an additional file that starts with the given prefix. This " "is used to generate separate binaries for validation, where " "`--split-input-file` normally combines all outputs into one. The " - "one combined output (`-o`) is still written."), + "one combined output (`-o`) is still written. Created files need to " + "be " + "removed manually once processed."), llvm::cl::init("")); TranslateFromMLIRRegistration toBinary( "serialize-spirv", "serialize SPIR-V dialect", - [](spirv::ModuleOp module, raw_ostream &output) { - return serializeModule(module, output, - {true, false, (validationFilesPrefix != ""), + [](spirv::ModuleOp moduleOp, raw_ostream &output) { + return serializeModule(moduleOp, output, + {true, false, !validationFilesPrefix.empty(), validationFilesPrefix}); }, [](DialectRegistry ®istry) { From dc922ea8e07496ea9df07062b6fc0fabf194d71c Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 12:59:44 +0000 Subject: [PATCH 5/9] Use createUniqueFile --- .../Target/SPIRV/TranslateRegistration.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index 8877461867bb3..a06de4063b2c2 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -79,10 +79,6 @@ void registerFromSPIRVTranslation() { // Serialization registration //===----------------------------------------------------------------------===// -// Static variable is probably not ideal, but it lets us have unique files names -// without taking additional parameters from `mlir-translate`. -static size_t validationFileCounter = 0; - static LogicalResult serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, const spirv::SerializationOptions &options) { @@ -106,18 +102,22 @@ serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, return failure(); } } - std::string errorMessage; - std::string filename = - options.validationFilePrefix + std::to_string(validationFileCounter++); - std::unique_ptr validationOutput = - openOutputFile(filename, &errorMessage); - if (!validationOutput) { - llvm::errs() << errorMessage << "\n"; + + SmallString<128> filename; + int fd; + + std::error_code errorCode = llvm::sys::fs::createUniqueFile( + options.validationFilePrefix + "%%%%%%", fd, filename); + if (errorCode) { + llvm::errs() << "error creating validation output file: " + << errorCode.message() << "\n"; return failure(); } - validationOutput->os().write(reinterpret_cast(binary.data()), - sizeInBytes); - validationOutput->keep(); + + llvm::raw_fd_ostream validationOutput(fd, /*shouldClose=*/true); + validationOutput.write(reinterpret_cast(binary.data()), + sizeInBytes); + validationOutput.flush(); } return mlir::success(); From 6c84de66bfd19c1e1b9db3b41198e5ba209d66ad Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 13:50:13 +0000 Subject: [PATCH 6/9] Add test --- mlir/test/Target/SPIRV/mlir-translate.mlir | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 mlir/test/Target/SPIRV/mlir-translate.mlir diff --git a/mlir/test/Target/SPIRV/mlir-translate.mlir b/mlir/test/Target/SPIRV/mlir-translate.mlir new file mode 100644 index 0000000000000..31437cc0a3917 --- /dev/null +++ b/mlir/test/Target/SPIRV/mlir-translate.mlir @@ -0,0 +1,29 @@ +// COM: Check that `--spirv-save-validation-files-with-prefix` generates +// COM: a correct number of files. + +// REQUIRES: shell +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mlir-translate --serialize-spirv --no-implicit-module --split-input-file --spirv-save-validation-files-with-prefix=%t/foo %s +// RUN: ls %t | wc -l | FileCheck %s +// RUN: rm -rf %t + +// CHECK: 4 + +spirv.module Logical GLSL450 requires #spirv.vce { +} + +// ----- + +spirv.module Logical GLSL450 requires #spirv.vce { +} + +// ----- + +spirv.module Logical GLSL450 requires #spirv.vce { +} + +// ----- + +spirv.module Logical GLSL450 requires #spirv.vce { +} From 2462ceb025f51c3cc6a34c065691c503f948612f Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 14:03:47 +0000 Subject: [PATCH 7/9] Update comment --- mlir/include/mlir/Target/SPIRV/Serialization.h | 12 +++++++++++- mlir/lib/Target/SPIRV/TranslateRegistration.cpp | 3 +-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Target/SPIRV/Serialization.h b/mlir/include/mlir/Target/SPIRV/Serialization.h index 67de6ccef487b..11089c67c2015 100644 --- a/mlir/include/mlir/Target/SPIRV/Serialization.h +++ b/mlir/include/mlir/Target/SPIRV/Serialization.h @@ -34,7 +34,17 @@ struct SerializationOptions { /// tool. This saved file is later used for validation. bool saveModuleForValidation = false; /// A prefix prepended to the file used when `saveModuleForValidation` - /// is set to `true`. + /// is set to `true`. This can either be a file prefix, or a relative or + /// or an absolute path followed by the prefix. For example: + /// + /// * "foo" - Create files with a `foo` prefix in the current working + /// directory. For example: `foo0`, `foo1` ... `fooN`. + /// + /// * "my/dir/foo" - Create files in `my/dir` with a `foo` prefix. The + /// `my/dir` need to exists. For example: `foo0`, `foo1` ... `fooN` + /// will be created and stored in `/my/dir`. + /// + /// * "/home/user/my/dir" - Same as above but using an absolute path. std::string validationFilePrefix = ""; }; diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index a06de4063b2c2..e6b5388835c3b 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -133,8 +133,7 @@ void registerToSPIRVTranslation() { "is used to generate separate binaries for validation, where " "`--split-input-file` normally combines all outputs into one. The " "one combined output (`-o`) is still written. Created files need to " - "be " - "removed manually once processed."), + "be removed manually once processed."), llvm::cl::init("")); TranslateFromMLIRRegistration toBinary( From ad50d492734d8251cfbbb5385a4abe6b1296daf6 Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 16:22:14 +0000 Subject: [PATCH 8/9] Address more feedback --- mlir/include/mlir/Target/SPIRV/Serialization.h | 9 ++++++--- mlir/lib/Target/SPIRV/TranslateRegistration.cpp | 8 ++++---- mlir/test/Target/SPIRV/mlir-translate.mlir | 8 +++----- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mlir/include/mlir/Target/SPIRV/Serialization.h b/mlir/include/mlir/Target/SPIRV/Serialization.h index 11089c67c2015..bc58093ead864 100644 --- a/mlir/include/mlir/Target/SPIRV/Serialization.h +++ b/mlir/include/mlir/Target/SPIRV/Serialization.h @@ -38,11 +38,14 @@ struct SerializationOptions { /// or an absolute path followed by the prefix. For example: /// /// * "foo" - Create files with a `foo` prefix in the current working - /// directory. For example: `foo0`, `foo1` ... `fooN`. + /// directory. For example: `fooXYZ123`, `fooABC456` ... `fooXXXXXX`. + /// The last 6 characters will be a unique combination as + /// generated by `llvm::sys::fs::createUniqueFile`. /// /// * "my/dir/foo" - Create files in `my/dir` with a `foo` prefix. The - /// `my/dir` need to exists. For example: `foo0`, `foo1` ... `fooN` - /// will be created and stored in `/my/dir`. + /// `my/dir` need to exists. For example: `fooXYZ123`, `fooABC456` ... + /// `fooXXXXXX` will be created and stored in `/my/dir`. Filenames + /// follow the same pattern as above. /// /// * "/home/user/my/dir" - Same as above but using an absolute path. std::string validationFilePrefix = ""; diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index e6b5388835c3b..12ae5f2852767 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -98,19 +98,19 @@ serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, llvm::StringRef parentDir = llvm::sys::path::parent_path(options.validationFilePrefix); if (!llvm::sys::fs::is_directory(parentDir)) { - llvm::errs() << "validation prefix directory does not exist\n"; + moduleOp.emitError("validation prefix directory does not exist\n"); return failure(); } } SmallString<128> filename; - int fd; + int fd = 0; std::error_code errorCode = llvm::sys::fs::createUniqueFile( options.validationFilePrefix + "%%%%%%", fd, filename); if (errorCode) { - llvm::errs() << "error creating validation output file: " - << errorCode.message() << "\n"; + moduleOp.emitError("error creating validation output file: ") + << errorCode.message() << "\n"; return failure(); } diff --git a/mlir/test/Target/SPIRV/mlir-translate.mlir b/mlir/test/Target/SPIRV/mlir-translate.mlir index 31437cc0a3917..a1cf1d4667c00 100644 --- a/mlir/test/Target/SPIRV/mlir-translate.mlir +++ b/mlir/test/Target/SPIRV/mlir-translate.mlir @@ -1,11 +1,9 @@ -// COM: Check that `--spirv-save-validation-files-with-prefix` generates -// COM: a correct number of files. +// Check that `--spirv-save-validation-files-with-prefix` generates +// a correct number of files. // REQUIRES: shell // RUN: rm -rf %t -// RUN: mkdir %t -// RUN: mlir-translate --serialize-spirv --no-implicit-module --split-input-file --spirv-save-validation-files-with-prefix=%t/foo %s -// RUN: ls %t | wc -l | FileCheck %s +// RUN: mkdir %t && mlir-translate --serialize-spirv --no-implicit-module --split-input-file --spirv-save-validation-files-with-prefix=%t/foo %s && ls %t | wc -l | FileCheck %s // RUN: rm -rf %t // CHECK: 4 From 45453b11d5e0ac0e7c880f0b3d2aee6d2f733f72 Mon Sep 17 00:00:00 2001 From: Igor Wodiany Date: Mon, 11 Aug 2025 16:53:52 +0000 Subject: [PATCH 9/9] Simplify return and break cmd --- mlir/lib/Target/SPIRV/TranslateRegistration.cpp | 15 ++++++--------- mlir/test/Target/SPIRV/mlir-translate.mlir | 4 +++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp index 12ae5f2852767..4391ee714c519 100644 --- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp +++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp @@ -97,10 +97,9 @@ serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, if (dirSeparator != std::string::npos) { llvm::StringRef parentDir = llvm::sys::path::parent_path(options.validationFilePrefix); - if (!llvm::sys::fs::is_directory(parentDir)) { - moduleOp.emitError("validation prefix directory does not exist\n"); - return failure(); - } + if (!llvm::sys::fs::is_directory(parentDir)) + return moduleOp.emitError( + "validation prefix directory does not exist\n"); } SmallString<128> filename; @@ -108,11 +107,9 @@ serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, std::error_code errorCode = llvm::sys::fs::createUniqueFile( options.validationFilePrefix + "%%%%%%", fd, filename); - if (errorCode) { - moduleOp.emitError("error creating validation output file: ") - << errorCode.message() << "\n"; - return failure(); - } + if (errorCode) + return moduleOp.emitError("error creating validation output file: ") + << errorCode.message() << "\n"; llvm::raw_fd_ostream validationOutput(fd, /*shouldClose=*/true); validationOutput.write(reinterpret_cast(binary.data()), diff --git a/mlir/test/Target/SPIRV/mlir-translate.mlir b/mlir/test/Target/SPIRV/mlir-translate.mlir index a1cf1d4667c00..9f91fc97dcaed 100644 --- a/mlir/test/Target/SPIRV/mlir-translate.mlir +++ b/mlir/test/Target/SPIRV/mlir-translate.mlir @@ -3,7 +3,9 @@ // REQUIRES: shell // RUN: rm -rf %t -// RUN: mkdir %t && mlir-translate --serialize-spirv --no-implicit-module --split-input-file --spirv-save-validation-files-with-prefix=%t/foo %s && ls %t | wc -l | FileCheck %s +// RUN: mkdir %t && mlir-translate --serialize-spirv --no-implicit-module \ +// RUN: --split-input-file --spirv-save-validation-files-with-prefix=%t/foo %s \ +// RUN: && ls %t | wc -l | FileCheck %s // RUN: rm -rf %t // CHECK: 4