Works well enough to load and optimize the simple shader; doesn't run it though
This commit is contained in:
@@ -21,11 +21,12 @@ add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
add_executable(bluebell
|
||||
src/bluebell.cpp src/bluebell.hpp
|
||||
src/pre-compiler.cpp src/pre-compiler.hpp src/compiler.cpp src/compiler.hpp)
|
||||
src/pre-compiler.cpp src/pre-compiler.hpp src/compiler.cpp src/compiler.hpp src/spv_meta.cpp src/spv_meta.hpp)
|
||||
|
||||
#target_link_libraries(bluebell PkgConfig::shaderc)
|
||||
|
||||
llvm_map_components_to_libnames(llvm_libs core)
|
||||
#print(${LLVM_AVAILABLE_LIBS})
|
||||
llvm_map_components_to_libnames(llvm_libs core native passes nativecodegen all)
|
||||
|
||||
target_link_libraries(bluebell shaderc_shared Boost::boost Boost::log ${llvm_libs})
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "bluebell.hpp"
|
||||
#include "pre-compiler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "spv_meta.hpp"
|
||||
|
||||
const char* SHADER_PREFIX = "#version 320 es\n\
|
||||
precision highp float;\
|
||||
@@ -31,6 +32,9 @@ const char* SHADER_SUFFIX = "void main() { \
|
||||
}";
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
build_spv_meta();
|
||||
InitLLVM();
|
||||
|
||||
std::stringstream shader_src;
|
||||
std::ifstream input(argv[1]);
|
||||
|
||||
@@ -38,6 +42,7 @@ int main(int argc, char** argv) {
|
||||
shader_src << input.rdbuf();
|
||||
shader_src << SHADER_SUFFIX;
|
||||
|
||||
|
||||
// std::cout << shader_src.str();
|
||||
|
||||
auto shader = pre_compile_shader(shader_src.str());
|
||||
|
||||
562
src/compiler.cpp
562
src/compiler.cpp
@@ -6,24 +6,38 @@
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Support/TargetRegistry.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <spirv-tools/libspirv.hpp>
|
||||
#include <spirv/1.0/spirv.hpp11>
|
||||
#include <spirv/1.0/GLSL.std.450.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include "spv_meta.hpp"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
|
||||
|
||||
class SpirvType {
|
||||
protected:
|
||||
llvm::Type *llvm = nullptr;
|
||||
std::string name;
|
||||
|
||||
virtual llvm::Type *build_llvm_type_impl(llvm::LLVMContext& ctx) = 0;
|
||||
public:
|
||||
virtual bool is_composite() const { return false; }
|
||||
virtual bool is_vector() const { return false; }
|
||||
virtual std::shared_ptr<SpirvType> inner_type() const { return nullptr; }
|
||||
void set_name(std::string& new_name) { name = new_name; }
|
||||
virtual ~SpirvType() = default;
|
||||
|
||||
llvm::Type *get_llvm_type() const { return llvm; }
|
||||
@@ -89,6 +103,9 @@ public:
|
||||
return inner;
|
||||
}
|
||||
|
||||
bool is_composite() const override {return true; }
|
||||
bool is_vector() const override { return true; }
|
||||
|
||||
explicit SpirvSequenceType(std::shared_ptr<SpirvType> &&inner): inner(inner) {}
|
||||
explicit SpirvSequenceType(std::shared_ptr<SpirvType> &inner): inner(inner) {}
|
||||
};
|
||||
@@ -139,7 +156,8 @@ class SpirvStructType: public SpirvType {
|
||||
public:
|
||||
std::vector<std::shared_ptr<SpirvType>> members;
|
||||
|
||||
explicit SpirvStructType(std::vector<std::shared_ptr<SpirvType>> members) : members(std::move(members)) {}
|
||||
explicit SpirvStructType(std::vector<std::shared_ptr<SpirvType>> members)
|
||||
: members(std::move(members)) {}
|
||||
|
||||
llvm::Type * build_llvm_type_impl(llvm::LLVMContext &ctx) override {
|
||||
std::vector<llvm::Type*> inner_types;
|
||||
@@ -148,6 +166,10 @@ public:
|
||||
inner_types.push_back(inner->get_llvm_type());
|
||||
}
|
||||
auto ret = llvm::StructType::create(ctx, llvm::ArrayRef<llvm::Type*>(inner_types));
|
||||
|
||||
if (!name.empty()) {
|
||||
ret->setName(name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@@ -186,6 +208,20 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class SpirvGlobalRef: public SpirvType {
|
||||
public:
|
||||
|
||||
explicit SpirvGlobalRef(llvm::Type* globalType) {
|
||||
llvm = globalType;
|
||||
}
|
||||
|
||||
protected:
|
||||
llvm::Type *build_llvm_type_impl(llvm::LLVMContext &ctx) override {
|
||||
BOOST_LOG_TRIVIAL(error) << " Tried to recreate the global type";
|
||||
return llvm;
|
||||
}
|
||||
};
|
||||
|
||||
std::string decode_string_arg(const uint32_t* args) {
|
||||
std::string result;
|
||||
for (int i = 0;; i++) {
|
||||
@@ -233,13 +269,19 @@ struct Constant {
|
||||
enum class Type {
|
||||
U32, U64, I32, I64,
|
||||
F32, F64,
|
||||
|
||||
Subclass,
|
||||
} type;
|
||||
|
||||
union {
|
||||
uint64_t ival;
|
||||
double fval;
|
||||
};
|
||||
protected:
|
||||
explicit Constant(Type type): type(Type::U32) {
|
||||
fval = 0;
|
||||
ival = 0;
|
||||
}
|
||||
public:
|
||||
|
||||
Constant(uint32_t val): type(Type::U32), ival(val) {}
|
||||
Constant(uint64_t val): type(Type::U64), ival(val) {}
|
||||
@@ -250,16 +292,62 @@ struct Constant {
|
||||
Constant(Type type, uint64_t val): type(type), ival(val) {}
|
||||
Constant(Type type, double val): type(type), fval(val) {}
|
||||
Constant(): type(Type::I32), ival(0) {}
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
class Variable {
|
||||
public:
|
||||
|
||||
void get_llvm_var() {
|
||||
|
||||
virtual ~Constant() = default;
|
||||
virtual llvm::Constant *get_llvm_const(llvm::LLVMContext &ctx) {
|
||||
switch (type) {
|
||||
case Type::U32:return llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), ival, false);
|
||||
case Type::U64:return llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), ival, false);
|
||||
case Type::I32:return llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), ival, true);
|
||||
case Type::I64:return llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), ival, true);
|
||||
case Type::F32:return llvm::ConstantFP::get(llvm::Type::getFloatTy(ctx), fval);
|
||||
case Type::F64:return llvm::ConstantFP::get(llvm::Type::getDoubleTy(ctx), fval);
|
||||
case Type::Subclass:
|
||||
BOOST_LOG_TRIVIAL(error) << "This should have been handled by the subclass";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ConstComposite: public Constant {
|
||||
llvm::Constant *val;
|
||||
|
||||
explicit ConstComposite(llvm::Constant* val): Constant(Type::Subclass), val(val) {}
|
||||
llvm::Constant * get_llvm_const(llvm::LLVMContext &ctx) override {
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
struct FunctionContext;
|
||||
|
||||
struct Global {
|
||||
std::shared_ptr<SpirvType> var_type;
|
||||
int element_no;
|
||||
// TODO: Collect binding info
|
||||
};
|
||||
|
||||
struct FunctionContext {
|
||||
std::map<uint32_t, llvm::Value*> values;
|
||||
std::map<uint32_t, llvm::Value*> speculative_values;
|
||||
llvm::Function *function;
|
||||
int cur_arg;
|
||||
bool in_prologue;
|
||||
std::map<uint32_t, llvm::BasicBlock*> basic_blocks;
|
||||
|
||||
FunctionContext(
|
||||
struct CompilerImpl &compiler,
|
||||
llvm::FunctionType *type,
|
||||
uint32_t id
|
||||
);
|
||||
|
||||
void gen_prologue(struct CompilerImpl &compiler);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct CompilerImpl {
|
||||
std::unique_ptr<llvm::LLVMContext> ctx;
|
||||
std::unique_ptr<llvm::Module> module;
|
||||
@@ -267,16 +355,24 @@ struct CompilerImpl {
|
||||
|
||||
std::map<uint32_t, spv_ext_inst_type_t> ext_insts;
|
||||
std::map<uint32_t, std::shared_ptr<SpirvType>> types;
|
||||
std::map<uint32_t, Constant> constants;
|
||||
std::map<uint32_t, std::shared_ptr<Constant>> constants;
|
||||
std::map<std::string, std::shared_ptr<EntryPoint>> entry_points;
|
||||
std::map<uint32_t, Variable> globals;
|
||||
std::map<uint32_t, Variable> function_vars;
|
||||
std::map<uint32_t, Global> globals;
|
||||
std::map<uint32_t, std::shared_ptr<FunctionContext>> functions;
|
||||
llvm::StructType* global_type;
|
||||
std::shared_ptr<SpirvType> global_type_spv;
|
||||
std::shared_ptr<FunctionContext> cur_function;
|
||||
|
||||
// decorations
|
||||
std::map<uint32_t, std::string> value_names;
|
||||
|
||||
public:
|
||||
CompilerImpl() {
|
||||
ctx = std::make_unique<llvm::LLVMContext>();
|
||||
module = std::make_unique<llvm::Module>("shader", *ctx);
|
||||
builder = std::make_unique<llvm::IRBuilder<>>(*ctx);
|
||||
global_type = llvm::StructType::create(*ctx, "globals");
|
||||
global_type_spv = std::make_shared<SpirvGlobalRef>(global_type->getPointerTo());
|
||||
}
|
||||
|
||||
bool process_module(std::vector<uint32_t> &spv_module) {
|
||||
@@ -297,6 +393,21 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void build_global_type() {
|
||||
std::vector<llvm::Type*> members;
|
||||
for (auto &global: globals) {
|
||||
members.push_back(global.second.var_type->get_llvm_type()->getPointerElementType());
|
||||
}
|
||||
global_type->setBody(members);
|
||||
}
|
||||
|
||||
void finish_tgv() {
|
||||
for (auto &type: types) {
|
||||
type.second->build_llvm_type(*ctx);
|
||||
}
|
||||
build_global_type();
|
||||
}
|
||||
|
||||
spv_result_t
|
||||
handle_spv_header(spv_endianness_t endianness, uint32_t magic, uint32_t version,
|
||||
uint32_t generator,
|
||||
@@ -312,7 +423,7 @@ public:
|
||||
std::string format_insn(const spv_parsed_instruction_t* insn) {
|
||||
|
||||
std::stringstream msg_stream;
|
||||
msg_stream << "Opcode(" << insn->opcode << "):";
|
||||
msg_stream << "Opcode(" << insn_names[insn->opcode] << "/" << insn->opcode << "):";
|
||||
|
||||
for (int i = 0; i < insn->num_operands; i++) {
|
||||
auto operand = &insn->operands[i];
|
||||
@@ -330,6 +441,8 @@ public:
|
||||
spv_result_t handle_spv_insn(const spv_parsed_instruction_t *insn) {
|
||||
uint32_t rid;
|
||||
uint32_t rty;
|
||||
bool has_rid = false;
|
||||
bool has_rty = false;
|
||||
uint32_t first_operand = insn->num_operands;
|
||||
auto idata = insn->words;
|
||||
|
||||
@@ -337,8 +450,10 @@ public:
|
||||
auto operand = &insn->operands[i];
|
||||
if (operand->type == SPV_OPERAND_TYPE_RESULT_ID) {
|
||||
rid = OP_WORD(i);
|
||||
has_rid = true;
|
||||
} else if (operand->type == SPV_OPERAND_TYPE_TYPE_ID) {
|
||||
rty = OP_WORD(i);
|
||||
has_rty = true;
|
||||
} else {
|
||||
first_operand = i;
|
||||
break;
|
||||
@@ -392,6 +507,20 @@ public:
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region 3.42.2 Debug insns
|
||||
case Op::OpSource:
|
||||
case Op::OpSourceContinued:
|
||||
case Op::OpSourceExtension:
|
||||
case Op::OpMemberName:
|
||||
case Op::OpString:
|
||||
case Op::OpLine:
|
||||
case Op::OpNoLine:
|
||||
break;
|
||||
case Op::OpName: {
|
||||
value_names[OP_WORD(0)] = decode_string_arg(OP_BYTES(1));
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region Annotations
|
||||
case Op::OpDecorate: {
|
||||
// TODO: save these for bindings
|
||||
@@ -427,7 +556,7 @@ public:
|
||||
break;
|
||||
}
|
||||
case Op::OpTypeArray: {
|
||||
types[rid] = std::make_shared<SpirvArrayType>(types[OP_WORD(1)], constants[OP_WORD(2)].ival);
|
||||
types[rid] = std::make_shared<SpirvArrayType>(types[OP_WORD(1)], constants[OP_WORD(2)]->ival);
|
||||
break;
|
||||
}
|
||||
// Op::OpTypeRuntimeArray: {}
|
||||
@@ -437,6 +566,10 @@ public:
|
||||
members.push_back(types[OP_WORD(i)]);
|
||||
}
|
||||
types[rid] = std::make_shared<SpirvStructType>(std::move(members));
|
||||
auto name_it = value_names.find(rid);
|
||||
if (name_it != value_names.end()) {
|
||||
types[rid]->set_name(name_it->second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op::OpTypePointer: {
|
||||
@@ -446,6 +579,7 @@ public:
|
||||
}
|
||||
case Op::OpTypeFunction: {
|
||||
std::vector<std::shared_ptr<SpirvType>> args;
|
||||
args.push_back(global_type_spv);
|
||||
for (int i = 2; i < insn->num_operands; i++) {
|
||||
args.push_back(types[OP_WORD(i)]);
|
||||
}
|
||||
@@ -453,13 +587,47 @@ public:
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region Constants
|
||||
//region 3.42.4 Extension instructions
|
||||
case Op::OpExtInst: {
|
||||
auto ext_set = ext_insts[OP_WORD(2)];
|
||||
auto ext_inst = OP_WORD(3);
|
||||
switch (ext_set) {
|
||||
case SPV_EXT_INST_TYPE_GLSL_STD_450: {
|
||||
switch (GLSLstd450(ext_inst)) {
|
||||
case GLSLstd450Cos: {
|
||||
auto val = cur_function->values[OP_WORD(4)];
|
||||
auto ty = val->getType();//->getScalarType();
|
||||
|
||||
put_value(rid, builder->CreateIntrinsic(llvm::Intrinsic::cos, ty, val));
|
||||
break;
|
||||
}
|
||||
// case GLSLstd450Atanh: {
|
||||
// auto val = cur_function->values[OP_WORD(4)];
|
||||
// auto ty = val->getType()->getScalarType();
|
||||
// put_value(rid, builder->CreateIntrinsic(llvm::Intrinsic::))
|
||||
// }
|
||||
default: {
|
||||
put_value(rid, builder->CreateFreeze(llvm::UndefValue::get(types[rty]->get_llvm_type())));
|
||||
BOOST_LOG_TRIVIAL(warning) << "Unhandled GLSL extinst " << ext_inst;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//endregion
|
||||
//region 3.42.7 Constant-creation instructions
|
||||
case Op::OpConstantTrue: {
|
||||
constants[rid] = Constant(uint32_t(1));
|
||||
constants[rid] = std::make_shared<Constant>(uint32_t(1));
|
||||
break;
|
||||
}
|
||||
case Op::OpConstantFalse:
|
||||
constants[rid] = Constant(uint32_t(0));
|
||||
constants[rid] = std::make_shared<Constant>(uint32_t(0));
|
||||
break;
|
||||
case Op::OpConstant: {
|
||||
auto &type = types[rty];
|
||||
@@ -475,60 +643,394 @@ public:
|
||||
bits = (uint64_t)OP_BYTES(2)[0]
|
||||
| ((uint64_t)(OP_BYTES(2)[1]) << 32);
|
||||
memcpy(&val, &bits, 8);
|
||||
constants[rid] = val;
|
||||
constants[rid] = std::make_shared<Constant>(val);
|
||||
break;
|
||||
case 32:
|
||||
// float
|
||||
memcpy(&fval, OP_BYTES(2), 4);
|
||||
constants[rid] = fval;
|
||||
constants[rid] = std::make_shared<Constant>(fval);
|
||||
break;
|
||||
case 16:
|
||||
// half; we don't implement this yet
|
||||
BOOST_LOG_TRIVIAL(warning) << "Half-precision floats incompletely implemented";
|
||||
constants[rid] = fval;
|
||||
constants[rid] = std::make_shared<Constant>(fval);
|
||||
break;
|
||||
}
|
||||
} else if (itype != nullptr) {
|
||||
uint64_t val = 0;
|
||||
switch (itype->width) {
|
||||
case 64:
|
||||
constants[rid] = (uint64_t)OP_BYTES(2)[0]
|
||||
| ((uint64_t)(OP_BYTES(2)[1]) << 32);
|
||||
constants[rid] = std::make_shared<Constant>((uint64_t)OP_BYTES(2)[0]
|
||||
| ((uint64_t)(OP_BYTES(2)[1]) << 32));
|
||||
break;
|
||||
case 32:
|
||||
constants[rid] = OP_WORD(2);
|
||||
constants[rid] = std::make_shared<Constant>(OP_WORD(2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region Variables
|
||||
case Op::OpVariable: {
|
||||
|
||||
case Op::OpConstantComposite: {
|
||||
auto &type = types[rty];
|
||||
type->build_llvm_type(*ctx);
|
||||
auto &typ_id = typeid(*type);
|
||||
std::vector<llvm::Constant*> elements;
|
||||
for (int i = 2; i < insn->num_operands; i++) {
|
||||
elements.push_back(constants[OP_WORD(i)]->get_llvm_const(*ctx));
|
||||
}
|
||||
|
||||
llvm::Constant *result = nullptr;
|
||||
if (typ_id == typeid(SpirvStructType)) {
|
||||
result = llvm::ConstantStruct::get((llvm::StructType*)type->get_llvm_type(),
|
||||
elements);
|
||||
} else if (typ_id == typeid(SpirvVectorType)) {
|
||||
result = llvm::ConstantVector::get(
|
||||
elements
|
||||
);
|
||||
} else if (typ_id == typeid(SpirvArrayType)) {
|
||||
result = llvm::ConstantArray::get(
|
||||
(llvm::ArrayType*)type->get_llvm_type(),
|
||||
elements
|
||||
);
|
||||
}
|
||||
constants[rid] = std::make_shared<ConstComposite>(result);
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region
|
||||
//region 3.42.8 Memory instructions
|
||||
case Op::OpVariable: {
|
||||
if (cur_function == nullptr) {
|
||||
int g_count = (int)globals.size();
|
||||
Global global = {
|
||||
.var_type = types[OP_WORD(0)],
|
||||
.element_no = g_count,
|
||||
};
|
||||
globals[OP_WORD(1)] = global;
|
||||
// TODO: handle initializer
|
||||
} else {
|
||||
put_value(rid, builder->CreateAlloca(types[rty]->get_llvm_type()->getPointerElementType(), nullptr, value_names[rid]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op::OpLoad: {
|
||||
put_value(rid, builder->CreateLoad(types[rty]->get_llvm_type(), cur_function->values[OP_WORD(2)]));
|
||||
break;
|
||||
}
|
||||
case Op::OpStore: {
|
||||
builder->CreateStore(cur_function->values[OP_WORD(1)], cur_function->values[OP_WORD(0)]);
|
||||
break;
|
||||
}
|
||||
case Op::OpAccessChain: {
|
||||
std::vector<llvm::Value*> indices;
|
||||
indices.push_back(builder->getInt32(0));
|
||||
for (int i = 3; i < insn->num_operands; i++) {
|
||||
// TODO: handle the case where the index is a value
|
||||
auto id = OP_WORD(i);
|
||||
indices.push_back(cur_function->values[id]);
|
||||
}
|
||||
auto ptr = cur_function->values[OP_WORD(2)];
|
||||
|
||||
put_value(rid, builder->CreateGEP(
|
||||
ptr->getType()->getPointerElementType(),
|
||||
cur_function->values[OP_WORD(2)],
|
||||
indices,
|
||||
value_names[rid]));
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
default:BOOST_LOG_TRIVIAL(info) << "Unhandled instruction " << format_insn(insn);
|
||||
//region 3.42.9 Function instructions
|
||||
case Op::OpFunction: {
|
||||
finish_tgv();
|
||||
auto ftype = types[OP_WORD(3)];
|
||||
auto ftype_llvm = (llvm::FunctionType*)ftype->get_llvm_type();
|
||||
cur_function = vivify_function(ftype_llvm, OP_WORD(1));
|
||||
if (!cur_function->function->empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Started assembling into " << cur_function->function->getName().str()
|
||||
<< " but it already had data";
|
||||
} else {
|
||||
builder->ClearInsertionPoint();
|
||||
cur_function->cur_arg = 1; // 0 is the global struct
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op::OpFunctionParameter: {
|
||||
put_value(rid, cur_function->function->getArg(cur_function->cur_arg++));
|
||||
break;
|
||||
}
|
||||
case Op::OpFunctionEnd: {
|
||||
cur_function = nullptr;
|
||||
break;
|
||||
}
|
||||
case Op::OpFunctionCall: {
|
||||
// Ugh, this is horrible. I need to create a function type here
|
||||
// because we might not have seen the target function yet
|
||||
std::vector<llvm::Type*> arg_types;
|
||||
std::vector<llvm::Value*> arg_values;
|
||||
arg_types.push_back(global_type->getPointerTo());
|
||||
arg_values.push_back(cur_function->function->getArg(0));
|
||||
for (int i = 3; i < insn->num_operands; i++) {
|
||||
llvm::Value* value = cur_function->values[OP_WORD(i)];
|
||||
arg_types.push_back(value->getType());
|
||||
arg_values.push_back(value);
|
||||
}
|
||||
auto ftype = llvm::FunctionType::get(
|
||||
types[OP_WORD(0)]->get_llvm_type(),
|
||||
arg_types,
|
||||
false);
|
||||
auto fn = vivify_function(ftype, OP_WORD(3));
|
||||
put_value(rid, builder->CreateCall(fn->function, arg_values));
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
// region 3.42.12 Composite instructions
|
||||
case Op::OpVectorShuffle: {
|
||||
std::vector<int> mask(OP_BYTES(4), OP_BYTES(insn->num_operands));
|
||||
auto value = builder->CreateShuffleVector(
|
||||
cur_function->values[OP_WORD(2)],
|
||||
cur_function->values[OP_WORD(3)],
|
||||
mask,
|
||||
value_names[rid]
|
||||
);
|
||||
put_value(rid, value);
|
||||
break;
|
||||
}
|
||||
case Op::OpCompositeConstruct: {
|
||||
llvm::Value* composite = llvm::UndefValue::get(types[rty]->get_llvm_type());
|
||||
int dst_idx = 0;
|
||||
bool dst_is_vector = composite->getType()->isVectorTy();
|
||||
for (int opin = 2; opin < insn->num_operands; opin++) {
|
||||
auto op = cur_function->values[OP_WORD(opin)];
|
||||
if (dst_is_vector && op->getType()->isVectorTy()) {
|
||||
// copy elementwise
|
||||
auto sty = (llvm::VectorType*)op->getType();
|
||||
for (unsigned int sidx = 0; sidx < sty->getElementCount().getFixedValue(); sidx++) {
|
||||
auto el = builder->CreateExtractElement(op, sidx);
|
||||
composite = builder->CreateInsertElement(composite, el, dst_idx++);
|
||||
}
|
||||
} else if (dst_is_vector) {
|
||||
composite = builder->CreateInsertElement(composite, op, dst_idx++);
|
||||
} else {
|
||||
composite = builder->CreateInsertValue(composite, op, dst_idx);
|
||||
dst_idx++;
|
||||
}
|
||||
}
|
||||
put_value(rid, composite);
|
||||
//
|
||||
break;
|
||||
}
|
||||
case Op::OpCompositeExtract: {
|
||||
auto value = cur_function->values[OP_WORD(2)];
|
||||
for (int opno = 3; opno < insn->num_operands; opno++) {
|
||||
auto op = OP_WORD(opno);
|
||||
if (value->getType()->isVectorTy()) {
|
||||
value = builder->CreateExtractElement(value, op);
|
||||
} else {
|
||||
value = builder->CreateExtractValue(value, op);
|
||||
}
|
||||
}
|
||||
put_value(rid, value);
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region 3.42.13 Arithmetic instructions
|
||||
case Op::OpFAdd: {
|
||||
auto value = builder->CreateFAdd(cur_function->values[OP_WORD(2)],
|
||||
cur_function->values[OP_WORD(3)]);
|
||||
put_value(rid, value);
|
||||
break;
|
||||
}
|
||||
case Op::OpFDiv: {
|
||||
auto value =
|
||||
builder->CreateFDiv(cur_function->values[OP_WORD(2)],
|
||||
cur_function->values[OP_WORD(3)]);
|
||||
put_value(rid, value);
|
||||
break;
|
||||
}
|
||||
case Op::OpVectorTimesScalar: {
|
||||
auto vty = (llvm::VectorType*)(types[rty]->get_llvm_type());
|
||||
auto scalar = builder->CreateVectorSplat(vty->getElementCount(), cur_function->values[OP_WORD(3)]);
|
||||
auto result = builder->CreateFMul(cur_function->values[OP_WORD(2)], scalar);
|
||||
put_value(rid, result);
|
||||
break;
|
||||
}
|
||||
//endregion
|
||||
//region 3.42.17 Control Flow instructions
|
||||
case Op::OpLabel: {
|
||||
llvm::BasicBlock *new_bb = cur_function->basic_blocks[rid];
|
||||
if (new_bb == nullptr) {
|
||||
auto label = boost::format("label_%1%") % rid;
|
||||
new_bb = cur_function->basic_blocks[rid] = llvm::BasicBlock::Create(*ctx, label.str(), cur_function->function);
|
||||
}
|
||||
builder->SetInsertPoint(new_bb);
|
||||
if (cur_function->in_prologue) {
|
||||
cur_function->gen_prologue(*this);
|
||||
cur_function->in_prologue = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op::OpReturn: {
|
||||
builder->CreateRetVoid();
|
||||
break;
|
||||
}
|
||||
|
||||
//endregion
|
||||
default:{
|
||||
BOOST_LOG_TRIVIAL(info) << "Unhandled instruction " << format_insn(insn);
|
||||
if (cur_function != nullptr && has_rid && has_rty) {
|
||||
auto value = builder->CreateFreeze(llvm::UndefValue::get(types[rty]->get_llvm_type()));
|
||||
put_value(rid, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_function != nullptr && has_rid && cur_function->values[rid] != nullptr) {
|
||||
auto name_it = value_names.find(rid);
|
||||
if (name_it != value_names.end()) {
|
||||
cur_function->values[rid]->setName(name_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
std::shared_ptr<FunctionContext> vivify_function(llvm::FunctionType *ftype, uint32_t id) {
|
||||
auto it = functions.find(id);
|
||||
if (it == functions.end()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Created function %" << id;
|
||||
|
||||
assert(ftype != nullptr);
|
||||
auto function = std::make_shared<FunctionContext>(*this, ftype, id);
|
||||
functions.emplace(id, function);
|
||||
return function;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Found pre-existing function %" << id;
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::Value* get_value(uint32_t id, llvm::Type* type) {
|
||||
auto value_it = cur_function->values.find(id);
|
||||
if (value_it != cur_function->values.end()) {
|
||||
return value_it->second;
|
||||
} else {
|
||||
auto value = builder->CreateFreeze(llvm::UndefValue::get(type));
|
||||
cur_function->values[id] = value;
|
||||
cur_function->speculative_values[id] = value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
void put_value(uint32_t id, llvm::Value* value) {
|
||||
auto sv_it = cur_function->speculative_values.find(id);
|
||||
if (sv_it != cur_function->speculative_values.end()) {
|
||||
sv_it->second->replaceAllUsesWith(value);
|
||||
cur_function->speculative_values.erase(sv_it);
|
||||
}
|
||||
cur_function->values[id] = value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void InitLLVM() {
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetDisassembler();
|
||||
}
|
||||
|
||||
|
||||
Compiler::Compiler(): impl(std::make_unique<CompilerImpl>()) {
|
||||
}
|
||||
|
||||
bool Compiler::compile(std::vector<uint32_t> &spv_module) {
|
||||
return impl->process_module(spv_module);
|
||||
auto ret = impl->process_module(spv_module);
|
||||
|
||||
impl->module->print(llvm::outs(), nullptr, false, true);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Optimizing";
|
||||
// start generating machine code
|
||||
auto target_triple = llvm::sys::getProcessTriple();
|
||||
std::string error;
|
||||
auto target = llvm::TargetRegistry::lookupTarget(target_triple, error);
|
||||
if (!target) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to load target: " << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::TargetOptions opt;
|
||||
auto CPU = llvm::sys::getHostCPUName();
|
||||
auto reloc_model = llvm::Optional<llvm::Reloc::Model>();
|
||||
auto code_model = llvm::Optional<llvm::CodeModel::Model>();
|
||||
auto target_machine = target->createTargetMachine(target_triple, CPU, "", opt, reloc_model, code_model, llvm::CodeGenOpt::Aggressive, true);
|
||||
impl->module->setDataLayout(target_machine->createDataLayout());
|
||||
impl->module->setTargetTriple(target_triple);
|
||||
|
||||
llvm::PassManagerBuilder pass_builder;
|
||||
target_machine->adjustPassManager(pass_builder);
|
||||
llvm::legacy::PassManager pass;
|
||||
pass_builder.populateModulePassManager(pass);
|
||||
pass.run(*impl->module);
|
||||
|
||||
impl->module->print(llvm::outs(), nullptr, false, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Compiler::~Compiler() = default;
|
||||
|
||||
FunctionContext::FunctionContext(struct CompilerImpl &compiler, llvm::FunctionType *ftype, uint32_t id) {
|
||||
|
||||
bool is_ep = false;
|
||||
std::string name;
|
||||
auto linkage = llvm::Function::ExternalLinkage;
|
||||
for (auto &ep: compiler.entry_points) {
|
||||
if (ep.second->func_id == id) {
|
||||
is_ep = true;
|
||||
name = ep.second->name;
|
||||
linkage = llvm::Function::ExternalLinkage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (name.empty()) {
|
||||
auto it = compiler.value_names.find(id);
|
||||
if (it != compiler.value_names.end()) {
|
||||
name = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &v: compiler.constants) {
|
||||
values[v.first] = v.second->get_llvm_const(*compiler.ctx);
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
std::stringstream name_builder;
|
||||
name_builder << "shaderfunc_" << id;
|
||||
name = name_builder.str();
|
||||
}
|
||||
|
||||
function = llvm::Function::Create(ftype, linkage, name, compiler.module.get());
|
||||
function->getArg(0)->setName("globals");
|
||||
in_prologue = true;
|
||||
|
||||
cur_arg = 1;
|
||||
}
|
||||
|
||||
void FunctionContext::gen_prologue(struct CompilerImpl &compiler) {
|
||||
// To be called after a basic block is created
|
||||
auto &builder = *compiler.builder;
|
||||
std::vector<llvm::Value*> indices;
|
||||
auto itype = llvm::Type::getInt32Ty(*compiler.ctx);
|
||||
indices.push_back(llvm::ConstantInt::get(itype, 0, false));
|
||||
indices.push_back(nullptr);
|
||||
for (auto &global: compiler.globals) {
|
||||
indices[1] = llvm::ConstantInt::get(itype, global.second.element_no, false);
|
||||
values[global.first] = builder.CreateGEP(
|
||||
compiler.global_type,
|
||||
function->getArg(0),
|
||||
indices,
|
||||
compiler.value_names[global.first]);
|
||||
}
|
||||
}
|
||||
|
||||
spv_result_t
|
||||
impl_parse_header(void *user_data, spv_endianness_t endian, uint32_t magic, uint32_t version, uint32_t generator,
|
||||
uint32_t id_bound, uint32_t reserved) {
|
||||
|
||||
@@ -15,4 +15,6 @@ public:
|
||||
|
||||
bool compile(std::vector<uint32_t> &spv_module);
|
||||
virtual ~Compiler();
|
||||
};
|
||||
};
|
||||
|
||||
void InitLLVM();
|
||||
@@ -13,7 +13,7 @@ std::shared_ptr<std::vector<uint32_t>> pre_compile_shader(const std::string &src
|
||||
shaderc::Compiler compiler;
|
||||
shaderc::CompileOptions options;
|
||||
options.SetSourceLanguage(shaderc_source_language_glsl);
|
||||
options.SetOptimizationLevel(shaderc_optimization_level_performance);
|
||||
// options.SetOptimizationLevel(shaderc_optimization_level_performance);
|
||||
options.SetTargetSpirv(shaderc_spirv_version_1_0);
|
||||
options.SetTargetEnvironment(
|
||||
shaderc_target_env_opengl_compat,
|
||||
|
||||
332
src/spv_insns.inc
Normal file
332
src/spv_insns.inc
Normal file
@@ -0,0 +1,332 @@
|
||||
{ 0, "OpNop" },
|
||||
{ 1, "OpUndef" },
|
||||
{ 2, "OpSourceContinued" },
|
||||
{ 3, "OpSource" },
|
||||
{ 4, "OpSourceExtension" },
|
||||
{ 5, "OpName" },
|
||||
{ 6, "OpMemberName" },
|
||||
{ 7, "OpString" },
|
||||
{ 8, "OpLine" },
|
||||
{ 10, "OpExtension" },
|
||||
{ 11, "OpExtInstImport" },
|
||||
{ 12, "OpExtInst" },
|
||||
{ 14, "OpMemoryModel" },
|
||||
{ 15, "OpEntryPoint" },
|
||||
{ 16, "OpExecutionMode" },
|
||||
{ 17, "OpCapability" },
|
||||
{ 19, "OpTypeVoid" },
|
||||
{ 20, "OpTypeBool" },
|
||||
{ 21, "OpTypeInt" },
|
||||
{ 22, "OpTypeFloat" },
|
||||
{ 23, "OpTypeVector" },
|
||||
{ 24, "OpTypeMatrix" },
|
||||
{ 25, "OpTypeImage" },
|
||||
{ 26, "OpTypeSampler" },
|
||||
{ 27, "OpTypeSampledImage" },
|
||||
{ 28, "OpTypeArray" },
|
||||
{ 29, "OpTypeRuntimeArray" },
|
||||
{ 30, "OpTypeStruct" },
|
||||
{ 31, "OpTypeOpaque" },
|
||||
{ 32, "OpTypePointer" },
|
||||
{ 33, "OpTypeFunction" },
|
||||
{ 34, "OpTypeEvent" },
|
||||
{ 35, "OpTypeDeviceEvent" },
|
||||
{ 36, "OpTypeReserveId" },
|
||||
{ 37, "OpTypeQueue" },
|
||||
{ 38, "OpTypePipe" },
|
||||
{ 39, "OpTypeForwardPointer" },
|
||||
{ 41, "OpConstantTrue" },
|
||||
{ 42, "OpConstantFalse" },
|
||||
{ 43, "OpConstant" },
|
||||
{ 44, "OpConstantComposite" },
|
||||
{ 45, "OpConstantSampler" },
|
||||
{ 46, "OpConstantNull" },
|
||||
{ 48, "OpSpecConstantTrue" },
|
||||
{ 49, "OpSpecConstantFalse" },
|
||||
{ 50, "OpSpecConstant" },
|
||||
{ 51, "OpSpecConstantComposite" },
|
||||
{ 52, "OpSpecConstantOp" },
|
||||
{ 54, "OpFunction" },
|
||||
{ 55, "OpFunctionParameter" },
|
||||
{ 56, "OpFunctionEnd" },
|
||||
{ 57, "OpFunctionCall" },
|
||||
{ 59, "OpVariable" },
|
||||
{ 60, "OpImageTexelPointer" },
|
||||
{ 61, "OpLoad" },
|
||||
{ 62, "OpStore" },
|
||||
{ 63, "OpCopyMemory" },
|
||||
{ 64, "OpCopyMemorySized" },
|
||||
{ 65, "OpAccessChain" },
|
||||
{ 66, "OpInBoundsAccessChain" },
|
||||
{ 67, "OpPtrAccessChain" },
|
||||
{ 68, "OpArrayLength" },
|
||||
{ 69, "OpGenericPtrMemSemantics" },
|
||||
{ 70, "OpInBoundsPtrAccessChain" },
|
||||
{ 71, "OpDecorate" },
|
||||
{ 72, "OpMemberDecorate" },
|
||||
{ 73, "OpDecorationGroup" },
|
||||
{ 74, "OpGroupDecorate" },
|
||||
{ 75, "OpGroupMemberDecorate" },
|
||||
{ 77, "OpVectorExtractDynamic" },
|
||||
{ 78, "OpVectorInsertDynamic" },
|
||||
{ 79, "OpVectorShuffle" },
|
||||
{ 80, "OpCompositeConstruct" },
|
||||
{ 81, "OpCompositeExtract" },
|
||||
{ 82, "OpCompositeInsert" },
|
||||
{ 83, "OpCopyObject" },
|
||||
{ 84, "OpTranspose" },
|
||||
{ 86, "OpSampledImage" },
|
||||
{ 87, "OpImageSampleImplicitLod" },
|
||||
{ 88, "OpImageSampleExplicitLod" },
|
||||
{ 89, "OpImageSampleDrefImplicitLod" },
|
||||
{ 90, "OpImageSampleDrefExplicitLod" },
|
||||
{ 91, "OpImageSampleProjImplicitLod" },
|
||||
{ 92, "OpImageSampleProjExplicitLod" },
|
||||
{ 93, "OpImageSampleProjDrefImplicitLod" },
|
||||
{ 94, "OpImageSampleProjDrefExplicitLod" },
|
||||
{ 95, "OpImageFetch" },
|
||||
{ 96, "OpImageGather" },
|
||||
{ 97, "OpImageDrefGather" },
|
||||
{ 98, "OpImageRead" },
|
||||
{ 99, "OpImageWrite" },
|
||||
{ 100, "OpImage" },
|
||||
{ 101, "OpImageQueryFormat" },
|
||||
{ 102, "OpImageQueryOrder" },
|
||||
{ 103, "OpImageQuerySizeLod" },
|
||||
{ 104, "OpImageQuerySize" },
|
||||
{ 105, "OpImageQueryLod" },
|
||||
{ 106, "OpImageQueryLevels" },
|
||||
{ 107, "OpImageQuerySamples" },
|
||||
{ 109, "OpConvertFToU" },
|
||||
{ 110, "OpConvertFToS" },
|
||||
{ 111, "OpConvertSToF" },
|
||||
{ 112, "OpConvertUToF" },
|
||||
{ 113, "OpUConvert" },
|
||||
{ 114, "OpSConvert" },
|
||||
{ 115, "OpFConvert" },
|
||||
{ 116, "OpQuantizeToF16" },
|
||||
{ 117, "OpConvertPtrToU" },
|
||||
{ 118, "OpSatConvertSToU" },
|
||||
{ 119, "OpSatConvertUToS" },
|
||||
{ 120, "OpConvertUToPtr" },
|
||||
{ 121, "OpPtrCastToGeneric" },
|
||||
{ 122, "OpGenericCastToPtr" },
|
||||
{ 123, "OpGenericCastToPtrExplicit" },
|
||||
{ 124, "OpBitcast" },
|
||||
{ 126, "OpSNegate" },
|
||||
{ 127, "OpFNegate" },
|
||||
{ 128, "OpIAdd" },
|
||||
{ 129, "OpFAdd" },
|
||||
{ 130, "OpISub" },
|
||||
{ 131, "OpFSub" },
|
||||
{ 132, "OpIMul" },
|
||||
{ 133, "OpFMul" },
|
||||
{ 134, "OpUDiv" },
|
||||
{ 135, "OpSDiv" },
|
||||
{ 136, "OpFDiv" },
|
||||
{ 137, "OpUMod" },
|
||||
{ 138, "OpSRem" },
|
||||
{ 139, "OpSMod" },
|
||||
{ 140, "OpFRem" },
|
||||
{ 141, "OpFMod" },
|
||||
{ 142, "OpVectorTimesScalar" },
|
||||
{ 143, "OpMatrixTimesScalar" },
|
||||
{ 144, "OpVectorTimesMatrix" },
|
||||
{ 145, "OpMatrixTimesVector" },
|
||||
{ 146, "OpMatrixTimesMatrix" },
|
||||
{ 147, "OpOuterProduct" },
|
||||
{ 148, "OpDot" },
|
||||
{ 149, "OpIAddCarry" },
|
||||
{ 150, "OpISubBorrow" },
|
||||
{ 151, "OpUMulExtended" },
|
||||
{ 152, "OpSMulExtended" },
|
||||
{ 154, "OpAny" },
|
||||
{ 155, "OpAll" },
|
||||
{ 156, "OpIsNan" },
|
||||
{ 157, "OpIsInf" },
|
||||
{ 158, "OpIsFinite" },
|
||||
{ 159, "OpIsNormal" },
|
||||
{ 160, "OpSignBitSet" },
|
||||
{ 161, "OpLessOrGreater" },
|
||||
{ 162, "OpOrdered" },
|
||||
{ 163, "OpUnordered" },
|
||||
{ 164, "OpLogicalEqual" },
|
||||
{ 165, "OpLogicalNotEqual" },
|
||||
{ 166, "OpLogicalOr" },
|
||||
{ 167, "OpLogicalAnd" },
|
||||
{ 168, "OpLogicalNot" },
|
||||
{ 169, "OpSelect" },
|
||||
{ 170, "OpIEqual" },
|
||||
{ 171, "OpINotEqual" },
|
||||
{ 172, "OpUGreaterThan" },
|
||||
{ 173, "OpSGreaterThan" },
|
||||
{ 174, "OpUGreaterThanEqual" },
|
||||
{ 175, "OpSGreaterThanEqual" },
|
||||
{ 176, "OpULessThan" },
|
||||
{ 177, "OpSLessThan" },
|
||||
{ 178, "OpULessThanEqual" },
|
||||
{ 179, "OpSLessThanEqual" },
|
||||
{ 180, "OpFOrdEqual" },
|
||||
{ 181, "OpFUnordEqual" },
|
||||
{ 182, "OpFOrdNotEqual" },
|
||||
{ 183, "OpFUnordNotEqual" },
|
||||
{ 184, "OpFOrdLessThan" },
|
||||
{ 185, "OpFUnordLessThan" },
|
||||
{ 186, "OpFOrdGreaterThan" },
|
||||
{ 187, "OpFUnordGreaterThan" },
|
||||
{ 188, "OpFOrdLessThanEqual" },
|
||||
{ 189, "OpFUnordLessThanEqual" },
|
||||
{ 190, "OpFOrdGreaterThanEqual" },
|
||||
{ 191, "OpFUnordGreaterThanEqual" },
|
||||
{ 194, "OpShiftRightLogical" },
|
||||
{ 195, "OpShiftRightArithmetic" },
|
||||
{ 196, "OpShiftLeftLogical" },
|
||||
{ 197, "OpBitwiseOr" },
|
||||
{ 198, "OpBitwiseXor" },
|
||||
{ 199, "OpBitwiseAnd" },
|
||||
{ 200, "OpNot" },
|
||||
{ 201, "OpBitFieldInsert" },
|
||||
{ 202, "OpBitFieldSExtract" },
|
||||
{ 203, "OpBitFieldUExtract" },
|
||||
{ 204, "OpBitReverse" },
|
||||
{ 205, "OpBitCount" },
|
||||
{ 207, "OpDPdx" },
|
||||
{ 208, "OpDPdy" },
|
||||
{ 209, "OpFwidth" },
|
||||
{ 210, "OpDPdxFine" },
|
||||
{ 211, "OpDPdyFine" },
|
||||
{ 212, "OpFwidthFine" },
|
||||
{ 213, "OpDPdxCoarse" },
|
||||
{ 214, "OpDPdyCoarse" },
|
||||
{ 215, "OpFwidthCoarse" },
|
||||
{ 218, "OpEmitVertex" },
|
||||
{ 219, "OpEndPrimitive" },
|
||||
{ 220, "OpEmitStreamVertex" },
|
||||
{ 221, "OpEndStreamPrimitive" },
|
||||
{ 224, "OpControlBarrier" },
|
||||
{ 225, "OpMemoryBarrier" },
|
||||
{ 227, "OpAtomicLoad" },
|
||||
{ 228, "OpAtomicStore" },
|
||||
{ 229, "OpAtomicExchange" },
|
||||
{ 230, "OpAtomicCompareExchange" },
|
||||
{ 231, "OpAtomicCompareExchangeWeak" },
|
||||
{ 232, "OpAtomicIIncrement" },
|
||||
{ 233, "OpAtomicIDecrement" },
|
||||
{ 234, "OpAtomicIAdd" },
|
||||
{ 235, "OpAtomicISub" },
|
||||
{ 236, "OpAtomicSMin" },
|
||||
{ 237, "OpAtomicUMin" },
|
||||
{ 238, "OpAtomicSMax" },
|
||||
{ 239, "OpAtomicUMax" },
|
||||
{ 240, "OpAtomicAnd" },
|
||||
{ 241, "OpAtomicOr" },
|
||||
{ 242, "OpAtomicXor" },
|
||||
{ 245, "OpPhi" },
|
||||
{ 246, "OpLoopMerge" },
|
||||
{ 247, "OpSelectionMerge" },
|
||||
{ 248, "OpLabel" },
|
||||
{ 249, "OpBranch" },
|
||||
{ 250, "OpBranchConditional" },
|
||||
{ 251, "OpSwitch" },
|
||||
{ 252, "OpKill" },
|
||||
{ 253, "OpReturn" },
|
||||
{ 254, "OpReturnValue" },
|
||||
{ 255, "OpUnreachable" },
|
||||
{ 256, "OpLifetimeStart" },
|
||||
{ 257, "OpLifetimeStop" },
|
||||
{ 259, "OpGroupAsyncCopy" },
|
||||
{ 260, "OpGroupWaitEvents" },
|
||||
{ 261, "OpGroupAll" },
|
||||
{ 262, "OpGroupAny" },
|
||||
{ 263, "OpGroupBroadcast" },
|
||||
{ 264, "OpGroupIAdd" },
|
||||
{ 265, "OpGroupFAdd" },
|
||||
{ 266, "OpGroupFMin" },
|
||||
{ 267, "OpGroupUMin" },
|
||||
{ 268, "OpGroupSMin" },
|
||||
{ 269, "OpGroupFMax" },
|
||||
{ 270, "OpGroupUMax" },
|
||||
{ 271, "OpGroupSMax" },
|
||||
{ 274, "OpReadPipe" },
|
||||
{ 275, "OpWritePipe" },
|
||||
{ 276, "OpReservedReadPipe" },
|
||||
{ 277, "OpReservedWritePipe" },
|
||||
{ 278, "OpReserveReadPipePackets" },
|
||||
{ 279, "OpReserveWritePipePackets" },
|
||||
{ 280, "OpCommitReadPipe" },
|
||||
{ 281, "OpCommitWritePipe" },
|
||||
{ 282, "OpIsValidReserveId" },
|
||||
{ 283, "OpGetNumPipePackets" },
|
||||
{ 284, "OpGetMaxPipePackets" },
|
||||
{ 285, "OpGroupReserveReadPipePackets" },
|
||||
{ 286, "OpGroupReserveWritePipePackets" },
|
||||
{ 287, "OpGroupCommitReadPipe" },
|
||||
{ 288, "OpGroupCommitWritePipe" },
|
||||
{ 291, "OpEnqueueMarker" },
|
||||
{ 292, "OpEnqueueKernel" },
|
||||
{ 293, "OpGetKernelNDrangeSubGroupCount" },
|
||||
{ 294, "OpGetKernelNDrangeMaxSubGroupSize" },
|
||||
{ 295, "OpGetKernelWorkGroupSize" },
|
||||
{ 296, "OpGetKernelPreferredWorkGroupSizeMultiple" },
|
||||
{ 297, "OpRetainEvent" },
|
||||
{ 298, "OpReleaseEvent" },
|
||||
{ 299, "OpCreateUserEvent" },
|
||||
{ 300, "OpIsValidEvent" },
|
||||
{ 301, "OpSetUserEventStatus" },
|
||||
{ 302, "OpCaptureEventProfilingInfo" },
|
||||
{ 303, "OpGetDefaultQueue" },
|
||||
{ 304, "OpBuildNDRange" },
|
||||
{ 305, "OpImageSparseSampleImplicitLod" },
|
||||
{ 306, "OpImageSparseSampleExplicitLod" },
|
||||
{ 307, "OpImageSparseSampleDrefImplicitLod" },
|
||||
{ 308, "OpImageSparseSampleDrefExplicitLod" },
|
||||
{ 309, "OpImageSparseSampleProjImplicitLod" },
|
||||
{ 310, "OpImageSparseSampleProjExplicitLod" },
|
||||
{ 311, "OpImageSparseSampleProjDrefImplicitLod" },
|
||||
{ 312, "OpImageSparseSampleProjDrefExplicitLod" },
|
||||
{ 313, "OpImageSparseFetch" },
|
||||
{ 314, "OpImageSparseGather" },
|
||||
{ 315, "OpImageSparseDrefGather" },
|
||||
{ 316, "OpImageSparseTexelsResident" },
|
||||
{ 317, "OpNoLine" },
|
||||
{ 318, "OpAtomicFlagTestAndSet" },
|
||||
{ 319, "OpAtomicFlagClear" },
|
||||
{ 320, "OpImageSparseRead" },
|
||||
{ 321, "OpSizeOf" },
|
||||
{ 322, "OpTypePipeStorage" },
|
||||
{ 323, "OpConstantPipeStorage" },
|
||||
{ 324, "OpCreatePipeFromPipeStorage" },
|
||||
{ 325, "OpGetKernelLocalSizeForSubgroupCount" },
|
||||
{ 326, "OpGetKernelMaxNumSubgroups" },
|
||||
{ 327, "OpTypeNamedBarrier" },
|
||||
{ 328, "OpNamedBarrierInitialize" },
|
||||
{ 329, "OpMemoryNamedBarrier" },
|
||||
{ 330, "OpModuleProcessed" },
|
||||
{ 331, "OpExecutionModeId" },
|
||||
{ 332, "OpDecorateId" },
|
||||
{ 4421, "OpSubgroupBallotKHR" },
|
||||
{ 4422, "OpSubgroupFirstInvocationKHR" },
|
||||
{ 4428, "OpSubgroupAllKHR" },
|
||||
{ 4429, "OpSubgroupAnyKHR" },
|
||||
{ 4430, "OpSubgroupAllEqualKHR" },
|
||||
{ 4432, "OpSubgroupReadInvocationKHR" },
|
||||
{ 5000, "OpGroupIAddNonUniformAMD" },
|
||||
{ 5001, "OpGroupFAddNonUniformAMD" },
|
||||
{ 5002, "OpGroupFMinNonUniformAMD" },
|
||||
{ 5003, "OpGroupUMinNonUniformAMD" },
|
||||
{ 5004, "OpGroupSMinNonUniformAMD" },
|
||||
{ 5005, "OpGroupFMaxNonUniformAMD" },
|
||||
{ 5006, "OpGroupUMaxNonUniformAMD" },
|
||||
{ 5007, "OpGroupSMaxNonUniformAMD" },
|
||||
{ 5011, "OpFragmentMaskFetchAMD" },
|
||||
{ 5012, "OpFragmentFetchAMD" },
|
||||
{ 5571, "OpSubgroupShuffleINTEL" },
|
||||
{ 5572, "OpSubgroupShuffleDownINTEL" },
|
||||
{ 5573, "OpSubgroupShuffleUpINTEL" },
|
||||
{ 5574, "OpSubgroupShuffleXorINTEL" },
|
||||
{ 5575, "OpSubgroupBlockReadINTEL" },
|
||||
{ 5576, "OpSubgroupBlockWriteINTEL" },
|
||||
{ 5577, "OpSubgroupImageBlockReadINTEL" },
|
||||
{ 5578, "OpSubgroupImageBlockWriteINTEL" },
|
||||
{ 5632, "OpDecorateStringGOOGLE" },
|
||||
{ 5633, "OpMemberDecorateStringGOOGLE" },
|
||||
22
src/spv_meta.cpp
Normal file
22
src/spv_meta.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by thequux on 5/25/22.
|
||||
//
|
||||
|
||||
#include "spv_meta.hpp"
|
||||
|
||||
static struct {
|
||||
uint16_t op_id;
|
||||
const char* name;
|
||||
} op_names_in[] = {
|
||||
#include "spv_insns.inc"
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
std::map<uint32_t, std::string> insn_names;
|
||||
|
||||
void build_spv_meta() {
|
||||
for (int i = 0; op_names_in[i].name != nullptr; i++) {
|
||||
auto &op = op_names_in[i];
|
||||
insn_names.emplace(op.op_id, op.name);
|
||||
}
|
||||
}
|
||||
11
src/spv_meta.hpp
Normal file
11
src/spv_meta.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by thequux on 5/25/22.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
extern std::map<uint32_t, std::string> insn_names;
|
||||
|
||||
void build_spv_meta();
|
||||
Reference in New Issue
Block a user