Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions mlir/include/mlir/Target/SPIRV/Serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "mlir/Support/LLVM.h"
#include <cstdint>
#include <string>

namespace mlir {
class MLIRContext;
Expand All @@ -27,12 +28,33 @@ 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`. 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: `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: `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 = "";
};

/// 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<uint32_t> &binary,
/// `moduleOp`.
LogicalResult serialize(ModuleOp moduleOp, SmallVectorImpl<uint32_t> &binary,
const SerializationOptions &options = {});

} // namespace spirv
Expand Down
62 changes: 55 additions & 7 deletions mlir/lib/Target/SPIRV/TranslateRegistration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
#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"

using namespace mlir;

Expand Down Expand Up @@ -76,24 +79,69 @@ void registerFromSPIRVTranslation() {
// Serialization registration
//===----------------------------------------------------------------------===//

static LogicalResult serializeModule(spirv::ModuleOp module,
raw_ostream &output) {
static LogicalResult
serializeModule(spirv::ModuleOp moduleOp, raw_ostream &output,
const spirv::SerializationOptions &options) {
SmallVector<uint32_t, 0> binary;
if (failed(spirv::serialize(module, binary)))
if (failed(spirv::serialize(moduleOp, binary)))
return failure();

output.write(reinterpret_cast<char *>(binary.data()),
binary.size() * sizeof(uint32_t));
size_t sizeInBytes = binary.size() * sizeof(uint32_t);

output.write(reinterpret_cast<char *>(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)) {
moduleOp.emitError("validation prefix directory does not exist\n");
return failure();
}
}

SmallString<128> filename;
int fd = 0;

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();
}

llvm::raw_fd_ostream validationOutput(fd, /*shouldClose=*/true);
validationOutput.write(reinterpret_cast<char *>(binary.data()),
sizeInBytes);
validationOutput.flush();
}

return mlir::success();
}

namespace mlir {
void registerToSPIRVTranslation() {
static llvm::cl::opt<std::string> 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. 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);
[](spirv::ModuleOp moduleOp, raw_ostream &output) {
return serializeModule(moduleOp, output,
{true, false, !validationFilesPrefix.empty(),
validationFilesPrefix});
},
[](DialectRegistry &registry) {
registry.insert<spirv::SPIRVDialect>();
Expand Down
27 changes: 27 additions & 0 deletions mlir/test/Target/SPIRV/mlir-translate.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Check that `--spirv-save-validation-files-with-prefix` generates
// a correct number of files.

// 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: rm -rf %t

// CHECK: 4

spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
}

// -----

spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
}

// -----

spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
}

// -----

spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
}
Loading