|
21 | 21 | #include "mlir/Target/SPIRV/Serialization.h"
|
22 | 22 | #include "mlir/Tools/mlir-translate/Translation.h"
|
23 | 23 | #include "llvm/ADT/StringRef.h"
|
| 24 | +#include "llvm/Support/FileSystem.h" |
24 | 25 | #include "llvm/Support/MemoryBuffer.h"
|
| 26 | +#include "llvm/Support/Path.h" |
25 | 27 | #include "llvm/Support/SourceMgr.h"
|
| 28 | +#include "llvm/Support/ToolOutputFile.h" |
26 | 29 |
|
27 | 30 | using namespace mlir;
|
28 | 31 |
|
@@ -76,24 +79,66 @@ void registerFromSPIRVTranslation() {
|
76 | 79 | // Serialization registration
|
77 | 80 | //===----------------------------------------------------------------------===//
|
78 | 81 |
|
79 |
| -static LogicalResult serializeModule(spirv::ModuleOp module, |
80 |
| - raw_ostream &output) { |
| 82 | +static LogicalResult |
| 83 | +serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output, |
| 84 | + const spirv::SerializationOptions &options) { |
81 | 85 | SmallVector<uint32_t, 0> binary;
|
82 |
| - if (failed(spirv::serialize(module, binary))) |
| 86 | + if (failed(spirv::serialize(moduleOp, binary))) |
83 | 87 | return failure();
|
84 | 88 |
|
85 |
| - output.write(reinterpret_cast<char *>(binary.data()), |
86 |
| - binary.size() * sizeof(uint32_t)); |
| 89 | + size_t sizeInBytes = binary.size() * sizeof(uint32_t); |
| 90 | + |
| 91 | + output.write(reinterpret_cast<char *>(binary.data()), sizeInBytes); |
| 92 | + |
| 93 | + if (options.saveModuleForValidation) { |
| 94 | + size_t dirSeparator = |
| 95 | + options.validationFilePrefix.find(llvm::sys::path::get_separator()); |
| 96 | + // If file prefix includes directory check if that directory exists. |
| 97 | + if (dirSeparator != std::string::npos) { |
| 98 | + llvm::StringRef parentDir = |
| 99 | + llvm::sys::path::parent_path(options.validationFilePrefix); |
| 100 | + if (!llvm::sys::fs::is_directory(parentDir)) |
| 101 | + return moduleOp.emitError( |
| 102 | + "validation prefix directory does not exist\n"); |
| 103 | + } |
| 104 | + |
| 105 | + SmallString<128> filename; |
| 106 | + int fd = 0; |
| 107 | + |
| 108 | + std::error_code errorCode = llvm::sys::fs::createUniqueFile( |
| 109 | + options.validationFilePrefix + "%%%%%%", fd, filename); |
| 110 | + if (errorCode) |
| 111 | + return moduleOp.emitError("error creating validation output file: ") |
| 112 | + << errorCode.message() << "\n"; |
| 113 | + |
| 114 | + llvm::raw_fd_ostream validationOutput(fd, /*shouldClose=*/true); |
| 115 | + validationOutput.write(reinterpret_cast<char *>(binary.data()), |
| 116 | + sizeInBytes); |
| 117 | + validationOutput.flush(); |
| 118 | + } |
87 | 119 |
|
88 | 120 | return mlir::success();
|
89 | 121 | }
|
90 | 122 |
|
91 | 123 | namespace mlir {
|
92 | 124 | void registerToSPIRVTranslation() {
|
| 125 | + static llvm::cl::opt<std::string> validationFilesPrefix( |
| 126 | + "spirv-save-validation-files-with-prefix", |
| 127 | + llvm::cl::desc( |
| 128 | + "When non-empty string is passed each serialized SPIR-V module is " |
| 129 | + "saved to an additional file that starts with the given prefix. This " |
| 130 | + "is used to generate separate binaries for validation, where " |
| 131 | + "`--split-input-file` normally combines all outputs into one. The " |
| 132 | + "one combined output (`-o`) is still written. Created files need to " |
| 133 | + "be removed manually once processed."), |
| 134 | + llvm::cl::init("")); |
| 135 | + |
93 | 136 | TranslateFromMLIRRegistration toBinary(
|
94 | 137 | "serialize-spirv", "serialize SPIR-V dialect",
|
95 |
| - [](spirv::ModuleOp module, raw_ostream &output) { |
96 |
| - return serializeModule(module, output); |
| 138 | + [](spirv::ModuleOp moduleOp, raw_ostream &output) { |
| 139 | + return serializeModule(moduleOp, output, |
| 140 | + {true, false, !validationFilesPrefix.empty(), |
| 141 | + validationFilesPrefix}); |
97 | 142 | },
|
98 | 143 | [](DialectRegistry ®istry) {
|
99 | 144 | registry.insert<spirv::SPIRVDialect>();
|
|
0 commit comments