Initial
This commit is contained in:
commit
d523862608
|
|
@ -0,0 +1,39 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(LUME LANGUAGES C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(LLVM_DIR "" CACHE PATH "Path to the LLVM build cmake directory")
|
||||||
|
set(MLIR_DIR "" CACHE PATH "Path to the MLIR build cmake directory")
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
find_package(LLVM REQUIRED CONFIG)
|
||||||
|
find_package(MLIR REQUIRED CONFIG)
|
||||||
|
|
||||||
|
include(AddLLVM)
|
||||||
|
include(TableGen)
|
||||||
|
|
||||||
|
add_subdirectory(lib)
|
||||||
|
|
||||||
|
add_executable(lume
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(lume PRIVATE
|
||||||
|
LUMELIB
|
||||||
|
LLVMCore
|
||||||
|
LLVMSupport
|
||||||
|
MLIRSupport
|
||||||
|
MLIRSPIRVTranslateRegistration
|
||||||
|
MLIRSPIRVBinaryUtils
|
||||||
|
MLIRLLVMDialect
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(lume PRIVATE
|
||||||
|
${LLVM_INCLUDE_DIRS}
|
||||||
|
${MLIR_INCLUDE_DIRS}
|
||||||
|
${CMAKE_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
# lume
|
||||||
|
|
||||||
|
lume is a compiler that converts SPIR-V binaries to MLIR and then to LLVM IR. This enables cross compilation of SPIR-V shaders to various target architectures through the LLVM toolchain
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- CMake 3.20 or higher
|
||||||
|
- LLVM (w/ MLIR support)
|
||||||
|
- C++17 compatible compiler
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DLLVM_DIR=/path/to/llvm/build/lib/cmake/llvm \
|
||||||
|
-DMLIR_DIR=/path/to/mlir/build/lib/cmake/mlir
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
lume input.spv -o output.mlir
|
||||||
|
lume input.spv --dump-mlir
|
||||||
|
lume input.spv --dump-all
|
||||||
|
lume - -o output.mlir
|
||||||
|
```
|
||||||
|
|
||||||
|
<h2>Options</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Input file</strong><br>
|
||||||
|
<code><input file></code><br>
|
||||||
|
<span style="margin-left:2em;">Input SPIR-V binary file (use <code>-</code> for stdin)</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Output file</strong><br>
|
||||||
|
<code>-o <output file></code><br>
|
||||||
|
<span style="margin-left:2em;">Specify output file (default: stdout)</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>SPIR-V MLIR Dump</strong><br>
|
||||||
|
<code>--dump-mlir</code><br>
|
||||||
|
<span style="margin-left:2em;">Dump the SPIR-V MLIR dialect</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Full Dump</strong><br>
|
||||||
|
<code>--dump-all</code><br>
|
||||||
|
<span style="margin-left:2em;">Dump all dialects and LLVM IR</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef LUMELIB_H
|
||||||
|
#define LUMELIB_H
|
||||||
|
|
||||||
|
#include "mlir/IR/MLIRContext.h"
|
||||||
|
#include "llvm/Support/LogicalResult.h"
|
||||||
|
#include <llvm/Support/MemoryBuffer.h>
|
||||||
|
#include <mlir/Dialect/SPIRV/IR/SPIRVOps.h>
|
||||||
|
#include <mlir/Dialect/SPIRV/IR/SPIRVDialect.h>
|
||||||
|
#include <mlir/Target/SPIRV/Deserialization.h>
|
||||||
|
|
||||||
|
namespace lume {
|
||||||
|
|
||||||
|
mlir::OwningOpRef<mlir::spirv::ModuleOp>
|
||||||
|
CompileSPVToMLIR(std::unique_ptr<llvm::MemoryBuffer> input,
|
||||||
|
mlir::MLIRContext &context,
|
||||||
|
mlir::spirv::DeserializationOptions &options);
|
||||||
|
|
||||||
|
llvm::LogicalResult ConvertSPVDialectToLLVMDialect(
|
||||||
|
mlir::MLIRContext &context,
|
||||||
|
mlir::ModuleOp *module);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
add_library(LUMELIB STATIC
|
||||||
|
LumeLib.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(LUMELIB PRIVATE
|
||||||
|
LLVMCore
|
||||||
|
LLVMSupport
|
||||||
|
MLIRSupport
|
||||||
|
MLIRSPIRVTranslateRegistration
|
||||||
|
MLIRSPIRVBinaryUtils
|
||||||
|
MLIRPass
|
||||||
|
MLIRSPIRVToLLVM
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(LUMELIB PRIVATE
|
||||||
|
${LLVM_INCLUDE_DIRS}
|
||||||
|
${MLIR_INCLUDE_DIRS}
|
||||||
|
${CMAKE_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "LumeLib.h"
|
||||||
|
|
||||||
|
#include <llvm/ADT/ArrayRef.h>
|
||||||
|
#include <llvm/Support/LogicalResult.h>
|
||||||
|
|
||||||
|
#include <mlir/Conversion/SPIRVToLLVM/SPIRVToLLVMPass.h>
|
||||||
|
#include <mlir/Dialect/SPIRV/IR/SPIRVEnums.h>
|
||||||
|
#include <mlir/IR/MLIRContext.h>
|
||||||
|
#include <mlir/Pass/PassManager.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace lume {
|
||||||
|
|
||||||
|
mlir::OwningOpRef<mlir::spirv::ModuleOp>
|
||||||
|
CompileSPVToMLIR(std::unique_ptr<llvm::MemoryBuffer> input,
|
||||||
|
mlir::MLIRContext &context,
|
||||||
|
mlir::spirv::DeserializationOptions &options) {
|
||||||
|
if (!input) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto *start = input->getBufferStart();
|
||||||
|
const auto size = input->getBufferSize();
|
||||||
|
|
||||||
|
if (size % sizeof(uint32_t) != 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto binary = llvm::ArrayRef(
|
||||||
|
reinterpret_cast<const uint32_t *>(start),
|
||||||
|
size / sizeof(uint32_t));
|
||||||
|
|
||||||
|
return mlir::spirv::deserialize(binary, &context, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::LogicalResult ConvertSPVDialectToLLVMDialect(
|
||||||
|
mlir::MLIRContext &context,
|
||||||
|
mlir::ModuleOp *module) {
|
||||||
|
if (!module) {
|
||||||
|
return llvm::failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
mlir::ConvertSPIRVToLLVMPassOptions options;
|
||||||
|
options.clientAPI = mlir::spirv::ClientAPI::Vulkan;
|
||||||
|
|
||||||
|
mlir::PassManager pm(&context);
|
||||||
|
pm.addPass(mlir::createConvertSPIRVToLLVMPass(options));
|
||||||
|
|
||||||
|
return pm.run(*module);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
#include "LumeLib.h"
|
||||||
|
|
||||||
|
#include <llvm/Support/CommandLine.h>
|
||||||
|
#include <llvm/Support/InitLLVM.h>
|
||||||
|
#include <llvm/Support/MemoryBuffer.h>
|
||||||
|
#include <llvm/Support/ToolOutputFile.h>
|
||||||
|
|
||||||
|
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
|
||||||
|
#include <mlir/Dialect/SPIRV/IR/SPIRVDialect.h>
|
||||||
|
#include <mlir/IR/BuiltinOps.h>
|
||||||
|
#include <mlir/IR/MLIRContext.h>
|
||||||
|
#include <mlir/InitAllTranslations.h>
|
||||||
|
#include <mlir/Support/FileUtilities.h>
|
||||||
|
#include <mlir/Target/SPIRV/Deserialization.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
llvm::cl::opt<std::string> inputFilename(
|
||||||
|
llvm::cl::Positional,
|
||||||
|
llvm::cl::desc("<input file>"),
|
||||||
|
llvm::cl::init("-"));
|
||||||
|
|
||||||
|
llvm::cl::opt<std::string> outputFilename(
|
||||||
|
"o",
|
||||||
|
llvm::cl::desc("Output file (default: stdout)"),
|
||||||
|
llvm::cl::value_desc("filename"),
|
||||||
|
llvm::cl::init("-"));
|
||||||
|
|
||||||
|
llvm::cl::opt<bool> dumpMLIR(
|
||||||
|
"dump-mlir",
|
||||||
|
llvm::cl::desc("Dump the SPIR-V MLIR dialect"),
|
||||||
|
llvm::cl::init(false));
|
||||||
|
|
||||||
|
llvm::cl::opt<bool> dumpAll(
|
||||||
|
"dump-all",
|
||||||
|
llvm::cl::desc("Dump all dialects and LLVM IR"),
|
||||||
|
llvm::cl::init(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
llvm::InitLLVM initLLVM(argc, argv);
|
||||||
|
llvm::cl::ParseCommandLineOptions(argc, argv, "Lume Compiler - SPIR-V to LLVM");
|
||||||
|
|
||||||
|
mlir::registerFromSPIRVTranslation();
|
||||||
|
|
||||||
|
std::string errorMessage;
|
||||||
|
auto input = mlir::openInputFile(inputFilename, &errorMessage);
|
||||||
|
if (!input) {
|
||||||
|
llvm::errs() << "Error: " << errorMessage << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlir::MLIRContext context;
|
||||||
|
context.loadDialect<mlir::spirv::SPIRVDialect>();
|
||||||
|
context.loadDialect<mlir::LLVM::LLVMDialect>();
|
||||||
|
|
||||||
|
mlir::spirv::DeserializationOptions options;
|
||||||
|
auto spvModule = lume::CompileSPVToMLIR(std::move(input), context, options);
|
||||||
|
|
||||||
|
if (!spvModule) {
|
||||||
|
llvm::errs() << "Error: Failed to deserialize SPIR-V binary\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlir::OpBuilder builder(&context);
|
||||||
|
auto topModule = mlir::ModuleOp::create(builder.getUnknownLoc());
|
||||||
|
topModule.getBody()->push_back(spvModule.release());
|
||||||
|
|
||||||
|
if (dumpMLIR || dumpAll) {
|
||||||
|
llvm::errs() << "=== MLIR SPIR-V Dialect ===\n";
|
||||||
|
topModule.dump();
|
||||||
|
llvm::errs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (llvm::failed(lume::ConvertSPVDialectToLLVMDialect(context, &topModule))) {
|
||||||
|
llvm::errs() << "Error: Failed to convert SPIR-V dialect to LLVM dialect\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dumpMLIR || dumpAll) {
|
||||||
|
llvm::errs() << "=== MLIR LLVM Dialect ===\n";
|
||||||
|
topModule.dump();
|
||||||
|
llvm::errs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputFilename != "-") {
|
||||||
|
auto output = mlir::openOutputFile(outputFilename, &errorMessage);
|
||||||
|
if (!output) {
|
||||||
|
llvm::errs() << "Error: " << errorMessage << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
topModule.print(output->os());
|
||||||
|
output->keep();
|
||||||
|
} else if (!dumpMLIR && !dumpAll) {
|
||||||
|
topModule.print(llvm::outs());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.0
|
||||||
|
; Generator: 0
|
||||||
|
; Bound: 8
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
|
||||||
|
; int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
|
%1 = OpTypeInt 32 1 ; i32 (signed)
|
||||||
|
%2 = OpTypeFunction %1 %1 %1 ; return i32, params (i32, i32)
|
||||||
|
|
||||||
|
%3 = OpFunction %1 None %2
|
||||||
|
%4 = OpFunctionParameter %1 ; param a
|
||||||
|
%5 = OpFunctionParameter %1 ; param b
|
||||||
|
%6 = OpLabel
|
||||||
|
%7 = OpIAdd %1 %4 %5 ; a + b
|
||||||
|
OpReturnValue %7
|
||||||
|
OpFunctionEnd
|
||||||
|
|
||||||
Loading…
Reference in New Issue