Stream SPIR-V instructions directly to a binary

Before this commit sirit generated a stream of tokens that would then be
inserted to the final SPIR-V binary. This design was carried from the
initial design of manually inserting opcodes into the code. Now that
all instructions but labels are inserted when their respective function
is called, the old design can be dropped in favor of generating a valid
stream of SPIR-V opcodes.

The API for variables is broken, but adopting the new one is trivial.
Instead of calling OpVariable and then adding a global or local
variable, OpVariable was removed and global or local variables are
generated when they are called.

Avoiding duplicates is now done with an std::unordered_set instead of
using a linear search jumping through vtables.
This commit is contained in:
ReinUsesLisp 2020-08-01 01:50:01 -03:00
parent c4ea8f4b76
commit 0b9ee36247
31 changed files with 651 additions and 1150 deletions

View file

@ -12,6 +12,7 @@
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <unordered_set>
#include <variant>
#include <vector>
@ -22,12 +23,16 @@ namespace Sirit {
constexpr std::uint32_t GENERATOR_MAGIC_NUMBER = 0;
class Op;
class Declarations;
class Operand;
class Stream;
using Literal =
std::variant<std::uint32_t, std::uint64_t, std::int32_t, std::int64_t, float, double>;
using Id = const Op*;
struct Id {
std::uint32_t value;
};
class Module {
public:
@ -52,12 +57,12 @@ public:
void SetMemoryModel(spv::AddressingModel addressing_model_, spv::MemoryModel memory_model_);
/// Adds an entry point.
void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string name,
void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string_view name,
std::span<const Id> interfaces = {});
/// Adds an entry point.
template <typename... Ts>
void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string name,
void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string_view name,
Ts&&... interfaces) {
AddEntryPoint(execution_model, std::move(entry_point), name,
std::span<const Id>{std::array{interfaces...}});
@ -89,19 +94,13 @@ public:
return AddLabel(OpLabel());
}
/**
* Adds a local variable to the code
* @param variable Variable to insert into code.
* @return Returns variable.
*/
Id AddLocalVariable(Id label);
/// Adds a local variable to the code
Id AddLocalVariable(Id result_type, spv::StorageClass storage_class,
std::optional<Id> initializer = {});
/**
* Adds a global variable
* @param variable Global variable to add.
* @return Returns variable.
*/
Id AddGlobalVariable(Id variable);
/// Adds a global variable
Id AddGlobalVariable(Id result_type, spv::StorageClass storage_class,
std::optional<Id> initializer = {});
// Types
@ -150,7 +149,7 @@ public:
}
/// Returns type opaque.
Id TypeOpaque(std::string name);
Id TypeOpaque(std::string_view name);
/// Returns type pointer.
Id TypePointer(spv::StorageClass storage_class, Id type);
@ -212,7 +211,7 @@ public:
Id OpFunction(Id result_type, spv::FunctionControlMask function_control, Id function_type);
/// Ends a function.
Id OpFunctionEnd();
void OpFunctionEnd();
/// Call a function.
Id OpFunctionCall(Id result_type, Id function, std::span<const Id> arguments = {});
@ -244,7 +243,7 @@ public:
Id OpLabel();
/// The block label instruction: Any reference to a block is through this ref.
Id OpLabel(std::string label_name) {
Id OpLabel(std::string_view label_name) {
return Name(OpLabel(), std::move(label_name));
}
@ -273,23 +272,20 @@ public:
/// Assign a name string to a reference.
/// @return target
Id Name(Id target, std::string name);
Id Name(Id target, std::string_view name);
/// Assign a name string to a member of a structure type.
/// @return type
Id MemberName(Id type, std::uint32_t member, std::string name);
Id MemberName(Id type, std::uint32_t member, std::string_view name);
/// Assign a Result <id> to a string for use by other debug instructions.
Id String(std::string string);
Id String(std::string_view string);
/// Add source-level location information
Id OpLine(Id file, Literal line, Literal column);
// Memory
/// Allocate an object in memory, resulting in a copy to it.
Id OpVariable(Id result_type, spv::StorageClass storage_class, Id initializer = nullptr);
/// Form a pointer to a texel of an image. Use of such a pointer is limited to atomic
/// operations.
Id OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample);
@ -1097,38 +1093,27 @@ public:
Id OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value);
private:
Id AddCode(std::unique_ptr<Op> op);
Id AddCode(spv::Op opcode, std::optional<std::uint32_t> id = {});
Id AddDeclaration(std::unique_ptr<Op> op);
void AddAnnotation(std::unique_ptr<Op> op);
Id GetGLSLstd450();
std::uint32_t version{};
std::uint32_t bound{1};
std::uint32_t bound{};
std::unordered_set<std::string> extensions;
std::unordered_set<spv::Capability> capabilities;
std::unordered_set<std::unique_ptr<Op>> ext_inst_import;
std::unique_ptr<Op> glsl_std_450;
std::optional<Id> glsl_std_450;
spv::AddressingModel addressing_model{spv::AddressingModel::Logical};
spv::MemoryModel memory_model{spv::MemoryModel::GLSL450};
std::vector<std::unique_ptr<Op>> entry_points;
std::vector<std::unique_ptr<Op>> execution_modes;
std::vector<std::unique_ptr<Op>> debug;
std::vector<std::unique_ptr<Op>> annotations;
std::vector<std::unique_ptr<Op>> declarations;
std::vector<Id> global_variables;
std::vector<Id> code;
std::vector<std::unique_ptr<Op>> code_store;
std::unique_ptr<Stream> ext_inst_imports;
std::unique_ptr<Stream> entry_points;
std::unique_ptr<Stream> execution_modes;
std::unique_ptr<Stream> debug;
std::unique_ptr<Stream> annotations;
std::unique_ptr<Declarations> declarations;
std::unique_ptr<Stream> global_variables;
std::unique_ptr<Stream> code;
};
} // namespace Sirit

View file

@ -1,16 +1,7 @@
add_library(sirit
../include/sirit/sirit.h
sirit.cpp
op.cpp
op.h
stream.cpp
stream.h
operand.cpp
operand.h
literal_number.cpp
literal_number.h
literal_string.cpp
literal_string.h
common_types.h
instructions/type.cpp
instructions/constant.cpp

View file

@ -4,32 +4,24 @@
* 3-Clause BSD License
*/
#include <memory>
#include <vector>
#include "common_types.h"
#include "op.h"
#include <span>
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::Decorate(Id target, spv::Decoration decoration, std::span<const Literal> literals) {
auto op{std::make_unique<Op>(spv::Op::OpDecorate)};
op->Add(target);
op->Add(static_cast<u32>(decoration));
op->Add(literals);
AddAnnotation(std::move(op));
return target;
annotations->Reserve(3 + literals.size());
return *annotations << spv::Op::OpDecorate << target << decoration << literals << EndOp{};
}
Id Module::MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration,
std::span<const Literal> literals) {
auto op{std::make_unique<Op>(spv::Op::OpMemberDecorate)};
op->Add(structure_type);
op->Add(member);
op->Add(static_cast<u32>(decoration));
op->Add(literals);
AddAnnotation(std::move(op));
return structure_type;
annotations->Reserve(4 + literals.size());
return *annotations << spv::Op::OpMemberDecorate << structure_type << member << decoration
<< literals << EndOp{};
}
} // namespace Sirit

View file

@ -4,35 +4,22 @@
* 3-Clause BSD License
*/
#include <memory>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
#define DEFINE_UNARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand); \
return AddCode(std::move(op)); \
code->Reserve(4); \
return *code << OpId{opcode, result_type} << operand << EndOp{}; \
}
#define DEFINE_BINARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand_1); \
op->Add(operand_2); \
return AddCode(std::move(op)); \
}
#define DEFINE_TRINARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand_1); \
op->Add(operand_2); \
op->Add(operand_3); \
return AddCode(std::move(op)); \
code->Reserve(5); \
return *code << OpId{opcode, result_type} << operand_1 << operand_2 << EndOp{}; \
}
DEFINE_UNARY(OpSNegate, spv::Op::OpSNegate)

View file

@ -4,145 +4,101 @@
* 3-Clause BSD License
*/
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicLoad, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpAtomicLoad, result_type} << pointer << memory << semantics
<< EndOp{};
}
Id Module::OpAtomicStore(Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicStore)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpAtomicStore} << pointer << memory << semantics << value
<< EndOp{};
}
Id Module::OpAtomicExchange(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicExchange, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicExchange, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicCompareExchange(Id result_type, Id pointer, Id memory, Id equal, Id unequal,
Id value, Id comparator) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicCompareExchange, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(equal);
op->Add(unequal);
op->Add(value);
op->Add(comparator);
return AddCode(std::move(op));
code->Reserve(9);
return *code << OpId{spv::Op::OpAtomicCompareExchange, result_type} << pointer << memory
<< equal << unequal << value << comparator << EndOp{};
}
Id Module::OpAtomicIIncrement(Id result_type, Id pointer, Id memory, Id semantics) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicIIncrement, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpAtomicIIncrement, result_type} << pointer << memory << semantics
<< EndOp{};
}
Id Module::OpAtomicIDecrement(Id result_type, Id pointer, Id memory, Id semantics) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicIDecrement, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpAtomicIDecrement, result_type} << pointer << memory << semantics
<< EndOp{};
}
Id Module::OpAtomicIAdd(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicIAdd, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicIAdd, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicISub(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicISub, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicISub, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicSMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicSMin, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicSMin, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicUMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicUMin, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicUMin, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicSMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicSMax, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicSMax, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicUMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicUMax, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicUMax, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicAnd(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicAnd, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicAnd, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicOr(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicOr, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicOr, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
Id Module::OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value) {
auto op{std::make_unique<Op>(spv::Op::OpAtomicXor, bound++, result_type)};
op->Add(pointer);
op->Add(memory);
op->Add(semantics);
op->Add(value);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpAtomicXor, result_type} << pointer << memory << semantics
<< value << EndOp{};
}
} // namespace Sirit

View file

@ -4,25 +4,20 @@
* 3-Clause BSD License
*/
#include <memory>
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpControlBarrier(Id execution, Id memory, Id semantics) {
auto op = std::make_unique<Op>(spv::Op::OpControlBarrier);
op->Add(execution);
op->Add(memory);
op->Add(semantics);
return AddCode(std::move(op));
code->Reserve(4);
return *code << spv::Op::OpControlBarrier << execution << memory << semantics << EndOp{};
}
Id Module::OpMemoryBarrier(Id scope, Id semantics) {
auto op = std::make_unique<Op>(spv::Op::OpMemoryBarrier);
op->Add(scope);
op->Add(semantics);
return AddCode(std::move(op));
code->Reserve(3);
return *code << spv::Op::OpMemoryBarrier << scope << semantics << EndOp{};
}
} // namespace Sirit

View file

@ -4,96 +4,73 @@
* 3-Clause BSD License
*/
#include <memory>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpShiftRightLogical(Id result_type, Id base, Id shift) {
auto op{std::make_unique<Op>(spv::Op::OpShiftRightLogical, bound++, result_type)};
op->Add(base);
op->Add(shift);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpShiftRightLogical, result_type} << base << shift << EndOp{};
}
Id Module::OpShiftRightArithmetic(Id result_type, Id base, Id shift) {
auto op{std::make_unique<Op>(spv::Op::OpShiftRightArithmetic, bound++, result_type)};
op->Add(base);
op->Add(shift);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpShiftRightArithmetic, result_type} << base << shift << EndOp{};
}
Id Module::OpShiftLeftLogical(Id result_type, Id base, Id shift) {
auto op{std::make_unique<Op>(spv::Op::OpShiftLeftLogical, bound++, result_type)};
op->Add(base);
op->Add(shift);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpShiftLeftLogical, result_type} << base << shift << EndOp{};
}
Id Module::OpBitwiseOr(Id result_type, Id operand_1, Id operand_2) {
auto op{std::make_unique<Op>(spv::Op::OpBitwiseOr, bound++, result_type)};
op->Add(operand_1);
op->Add(operand_2);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpBitwiseOr, result_type} << operand_1 << operand_2 << EndOp{};
}
Id Module::OpBitwiseXor(Id result_type, Id operand_1, Id operand_2) {
auto op{std::make_unique<Op>(spv::Op::OpBitwiseXor, bound++, result_type)};
op->Add(operand_1);
op->Add(operand_2);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpBitwiseXor, result_type} << operand_1 << operand_2 << EndOp{};
}
Id Module::OpBitwiseAnd(Id result_type, Id operand_1, Id operand_2) {
auto op{std::make_unique<Op>(spv::Op::OpBitwiseAnd, bound++, result_type)};
op->Add(operand_1);
op->Add(operand_2);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpBitwiseAnd, result_type} << operand_1 << operand_2 << EndOp{};
}
Id Module::OpNot(Id result_type, Id operand) {
auto op{std::make_unique<Op>(spv::Op::OpNot, bound++, result_type)};
op->Add(operand);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpNot, result_type} << operand << EndOp{};
}
Id Module::OpBitFieldInsert(Id result_type, Id base, Id insert, Id offset, Id count) {
auto op{std::make_unique<Op>(spv::Op::OpBitFieldInsert, bound++, result_type)};
op->Add(base);
op->Add(insert);
op->Add(offset);
op->Add(count);
return AddCode(std::move(op));
code->Reserve(7);
return *code << OpId{spv::Op::OpBitFieldInsert, result_type} << base << insert << offset
<< count << EndOp{};
}
Id Module::OpBitFieldSExtract(Id result_type, Id base, Id offset, Id count) {
auto op{std::make_unique<Op>(spv::Op::OpBitFieldSExtract, bound++, result_type)};
op->Add(base);
op->Add(offset);
op->Add(count);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpBitFieldSExtract, result_type} << base << offset << count
<< EndOp{};
}
Id Module::OpBitFieldUExtract(Id result_type, Id base, Id offset, Id count) {
auto op{std::make_unique<Op>(spv::Op::OpBitFieldUExtract, bound++, result_type)};
op->Add(base);
op->Add(offset);
op->Add(count);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpBitFieldUExtract, result_type} << base << offset << count
<< EndOp{};
}
Id Module::OpBitReverse(Id result_type, Id base) {
auto op{std::make_unique<Op>(spv::Op::OpBitReverse, bound++, result_type)};
op->Add(base);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpBitReverse, result_type} << base << EndOp{};
}
Id Module::OpBitCount(Id result_type, Id base) {
auto op{std::make_unique<Op>(spv::Op::OpBitCount, bound++, result_type)};
op->Add(base);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpBitCount, result_type} << base << EndOp{};
}
} // namespace Sirit

View file

@ -5,42 +5,44 @@
*/
#include <cassert>
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::ConstantTrue(Id result_type) {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpConstantTrue, bound, result_type));
declarations->Reserve(3);
return *declarations << OpId{spv::Op::OpConstantTrue, result_type} << EndOp{};
}
Id Module::ConstantFalse(Id result_type) {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpConstantFalse, bound, result_type));
declarations->Reserve(3);
return *declarations << OpId{spv::Op::OpConstantFalse, result_type} << EndOp{};
}
Id Module::Constant(Id result_type, const Literal& literal) {
auto op{std::make_unique<Op>(spv::Op::OpConstant, bound, result_type)};
op->Add(literal);
return AddDeclaration(std::move(op));
declarations->Reserve(3 + 2);
return *declarations << OpId{spv::Op::OpConstant, result_type} << literal << EndOp{};
}
Id Module::ConstantComposite(Id result_type, std::span<const Id> constituents) {
auto op{std::make_unique<Op>(spv::Op::OpConstantComposite, bound, result_type)};
op->Add(constituents);
return AddDeclaration(std::move(op));
declarations->Reserve(3 + constituents.size());
return *declarations << OpId{spv::Op::OpConstantComposite, result_type} << constituents
<< EndOp{};
}
Id Module::ConstantSampler(Id result_type, spv::SamplerAddressingMode addressing_mode,
bool normalized, spv::SamplerFilterMode filter_mode) {
auto op{std::make_unique<Op>(spv::Op::OpConstantSampler, bound, result_type)};
op->Add(static_cast<u32>(addressing_mode));
op->Add(normalized ? 1 : 0);
op->Add(static_cast<u32>(filter_mode));
return AddDeclaration(std::move(op));
declarations->Reserve(6);
return *declarations << OpId{spv::Op::OpConstantSampler, result_type} << addressing_mode
<< normalized << filter_mode << EndOp{};
}
Id Module::ConstantNull(Id result_type) {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpConstantNull, bound, result_type));
declarations->Reserve(3);
return *declarations << OpId{spv::Op::OpConstantNull, result_type} << EndOp{};
}
} // namespace Sirit

View file

@ -4,18 +4,16 @@
* 3-Clause BSD License
*/
#include <memory>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
#define DEFINE_UNARY(opcode) \
Id Module::opcode(Id result_type, Id operand) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(operand); \
return AddCode(std::move(op)); \
code->Reserve(4); \
return *code << OpId{spv::Op::opcode, result_type} << operand << EndOp{}; \
}
DEFINE_UNARY(OpConvertFToU)

View file

@ -4,44 +4,33 @@
* 3-Clause BSD License
*/
#include <memory>
#include <string>
#include "op.h"
#include "sirit/sirit.h"
#include "common_types.h"
#include "stream.h"
namespace Sirit {
Id Module::Name(Id target, std::string name) {
auto op{std::make_unique<Op>(spv::Op::OpName)};
op->Add(target);
op->Add(std::move(name));
debug.push_back(std::move(op));
Id Module::Name(Id target, std::string_view name) {
debug->Reserve(3 + WordsInString(name));
*debug << spv::Op::OpName << target << name << EndOp{};
return target;
}
Id Module::MemberName(Id type, u32 member, std::string name) {
auto op{std::make_unique<Op>(spv::Op::OpMemberName)};
op->Add(type);
op->Add(member);
op->Add(std::move(name));
debug.push_back(std::move(op));
Id Module::MemberName(Id type, u32 member, std::string_view name) {
debug->Reserve(4 + WordsInString(name));
*debug << spv::Op::OpMemberName << type << member << name << EndOp{};
return type;
}
Id Module::String(std::string string) {
auto op{std::make_unique<Op>(spv::Op::OpString, bound++)};
op->Add(std::move(string));
const auto id = op.get();
debug.push_back(std::move(op));
return id;
Id Module::String(std::string_view string) {
debug->Reserve(3 + WordsInString(string));
return *debug << OpId{spv::Op::OpString} << string << EndOp{};
}
Id Module::OpLine(Id file, Literal line, Literal column) {
auto op{std::make_unique<Op>(spv::Op::OpLine)};
op->Add(file);
op->Add(line);
op->Add(column);
return AddCode(std::move(op));
debug->Reserve(4);
return *debug << spv::Op::OpLine << file << line << column << EndOp{};
}
} // namespace Sirit

View file

@ -4,20 +4,18 @@
* 3-Clause BSD License
*/
#include <memory>
#include <spirv/unified1/GLSL.std.450.h>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpExtInst(Id result_type, Id set, u32 instruction, std::span<const Id> operands) {
auto op{std::make_unique<Op>(spv::Op::OpExtInst, bound++, result_type)};
op->Add(set);
op->Add(instruction);
op->Add(operands);
return AddCode(std::move(op));
code->Reserve(5 + operands.size());
return *code << OpId{spv::Op::OpExtInst, result_type} << set << instruction << operands
<< EndOp{};
}
#define DEFINE_UNARY(funcname, opcode) \
@ -74,4 +72,5 @@ DEFINE_UNARY(OpFindUMsb, GLSLstd450FindUMsb)
DEFINE_UNARY(OpInterpolateAtCentroid, GLSLstd450InterpolateAtCentroid)
DEFINE_BINARY(OpInterpolateAtSample, GLSLstd450InterpolateAtSample)
DEFINE_BINARY(OpInterpolateAtOffset, GLSLstd450InterpolateAtOffset)
} // namespace Sirit

View file

@ -5,79 +5,70 @@
*/
#include <cassert>
#include <vector>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control,
std::span<const Id> literals) {
auto op{std::make_unique<Op>(spv::Op::OpLoopMerge)};
op->Add(merge_block);
op->Add(continue_target);
op->Add(static_cast<u32>(loop_control));
op->Add(literals);
return AddCode(std::move(op));
code->Reserve(4 + literals.size());
return *code << spv::Op::OpLoopMerge << merge_block << continue_target << loop_control
<< literals << EndOp{};
}
Id Module::OpSelectionMerge(Id merge_block, spv::SelectionControlMask selection_control) {
auto op{std::make_unique<Op>(spv::Op::OpSelectionMerge)};
op->Add(merge_block);
op->Add(static_cast<u32>(selection_control));
return AddCode(std::move(op));
code->Reserve(3);
return *code << spv::Op::OpSelectionMerge << merge_block << selection_control << EndOp{};
}
Id Module::OpLabel() {
return code_store.emplace_back(std::make_unique<Op>(spv::Op::OpLabel, bound++)).get();
return Id{++bound};
}
Id Module::OpBranch(Id target_label) {
auto op{std::make_unique<Op>(spv::Op::OpBranch)};
op->Add(target_label);
return AddCode(std::move(op));
code->Reserve(2);
return *code << spv::Op::OpBranch << target_label << EndOp{};
}
Id Module::OpBranchConditional(Id condition, Id true_label, Id false_label, u32 true_weight,
u32 false_weight) {
auto op{std::make_unique<Op>(spv::Op::OpBranchConditional)};
op->Add(condition);
op->Add(true_label);
op->Add(false_label);
code->Reserve(6);
*code << spv::Op::OpBranchConditional << condition << true_label << false_label;
if (true_weight != 0 || false_weight != 0) {
op->Add(true_weight);
op->Add(false_weight);
*code << true_weight << false_weight;
}
return AddCode(std::move(op));
return *code << EndOp{};
}
Id Module::OpSwitch(Id selector, Id default_label, std::span<const Literal> literals,
std::span<const Id> labels) {
const std::size_t size = literals.size();
assert(literals.size() == labels.size());
auto op{std::make_unique<Op>(spv::Op::OpSwitch)};
op->Add(selector);
op->Add(default_label);
const size_t size = literals.size();
code->Reserve(3 + size * 2);
*code << spv::Op::OpSwitch << selector << default_label;
for (std::size_t i = 0; i < size; ++i) {
op->Add(literals[i]);
op->Add(labels[i]);
*code << literals[i] << labels[i];
}
return AddCode(std::move(op));
return *code << EndOp{};
}
Id Module::OpReturn() {
return AddCode(spv::Op::OpReturn);
code->Reserve(1);
return *code << spv::Op::OpReturn << EndOp{};
}
Id Module::OpReturnValue(Id value) {
auto op{std::make_unique<Op>(spv::Op::OpReturnValue)};
op->Add(value);
return AddCode(std::move(op));
code->Reserve(2);
return *code << spv::Op::OpReturnValue << value << EndOp{};
}
Id Module::OpKill() {
return AddCode(std::make_unique<Op>(spv::Op::OpKill));
code->Reserve(1);
return *code << spv::Op::OpKill << EndOp{};
}
} // namespace Sirit

View file

@ -4,28 +4,26 @@
* 3-Clause BSD License
*/
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpFunction(Id result_type, spv::FunctionControlMask function_control, Id function_type) {
auto op{std::make_unique<Op>(spv::Op::OpFunction, bound++, result_type)};
op->Add(static_cast<u32>(function_control));
op->Add(function_type);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpFunction, result_type} << function_control << function_type
<< EndOp{};
}
Id Module::OpFunctionEnd() {
return AddCode(spv::Op::OpFunctionEnd);
void Module::OpFunctionEnd() {
code->Reserve(1);
*code << spv::Op::OpFunctionEnd << EndOp{};
}
Id Module::OpFunctionCall(Id result_type, Id function, std::span<const Id> arguments) {
auto op{std::make_unique<Op>(spv::Op::OpFunctionCall, bound++, result_type)};
op->Add(function);
op->Add(arguments);
return AddCode(std::move(op));
code->Reserve(4 + arguments.size());
return *code << OpId{spv::Op::OpFunctionCall, result_type} << function << arguments << EndOp{};
}
} // namespace Sirit

View file

@ -4,48 +4,42 @@
* 3-Clause BSD License
*/
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
Id Module::OpSubgroupBallotKHR(Id result_type, Id predicate) {
auto op = std::make_unique<Op>(spv::Op::OpSubgroupBallotKHR, bound++, result_type);
op->Add(predicate);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpSubgroupBallotKHR, result_type} << predicate << EndOp{};
}
Id Module::OpSubgroupReadInvocationKHR(Id result_type, Id value, Id index) {
auto op = std::make_unique<Op>(spv::Op::OpSubgroupReadInvocationKHR, bound++, result_type);
op->Add(value);
op->Add(index);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpSubgroupReadInvocationKHR, result_type} << value << index
<< EndOp{};
}
Id Module::OpSubgroupAllKHR(Id result_type, Id predicate) {
auto op = std::make_unique<Op>(spv::Op::OpSubgroupAllKHR, bound++, result_type);
op->Add(predicate);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpSubgroupAllKHR, result_type} << predicate << EndOp{};
}
Id Module::OpSubgroupAnyKHR(Id result_type, Id predicate) {
auto op = std::make_unique<Op>(spv::Op::OpSubgroupAnyKHR, bound++, result_type);
op->Add(predicate);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpSubgroupAnyKHR, result_type} << predicate << EndOp{};
}
Id Module::OpSubgroupAllEqualKHR(Id result_type, Id predicate) {
auto op = std::make_unique<Op>(spv::Op::OpSubgroupAllEqualKHR, bound++, result_type);
op->Add(predicate);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpSubgroupAllEqualKHR, result_type} << predicate << EndOp{};
}
Id Module::OpGroupNonUniformShuffleXor(Id result_type, spv::Scope scope, Id value, Id mask) {
auto op = std::make_unique<Op>(spv::Op::OpGroupNonUniformShuffleXor, bound++, result_type);
op->Add(static_cast<u32>(scope));
op->Add(value);
op->Add(mask);
return AddCode(std::move(op));
code->Reserve(6);
return *code << OpId{spv::Op::OpGroupNonUniformShuffleXor, result_type} << scope << value
<< mask << EndOp{};
}
} // namespace Sirit

View file

@ -4,79 +4,58 @@
* 3-Clause BSD License
*/
#include "common_types.h"
#include "op.h"
#include <cassert>
#include "sirit/sirit.h"
namespace Sirit {
#include "stream.h"
static void AddImageOperands(Op* op, std::optional<spv::ImageOperandsMask> image_operands,
std::span<const Id> operands) {
if (!image_operands)
return;
op->Add(static_cast<u32>(*image_operands));
op->Add(operands);
}
namespace Sirit {
#define DEFINE_IMAGE_OP(opcode) \
Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \
std::optional<spv::ImageOperandsMask> image_operands, \
std::span<const Id> operands) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(sampled_image); \
op->Add(coordinate); \
AddImageOperands(op.get(), image_operands, operands); \
return AddCode(std::move(op)); \
code->Reserve(6 + operands.size()); \
return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate \
<< image_operands << operands << EndOp{}; \
}
#define DEFINE_IMAGE_EXP_OP(opcode) \
Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \
spv::ImageOperandsMask image_operands, std::span<const Id> operands) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(sampled_image); \
op->Add(coordinate); \
op->Add(static_cast<u32>(image_operands)); \
op->Add(operands); \
return AddCode(std::move(op)); \
code->Reserve(7 + operands.size()); \
return *code << OpId{spv::Op::OpDecorate, result_type} << sampled_image << coordinate \
<< image_operands << operands << EndOp{}; \
}
#define DEFINE_IMAGE_EXTRA_OP(opcode) \
Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \
std::optional<spv::ImageOperandsMask> image_operands, \
std::span<const Id> operands) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(sampled_image); \
op->Add(coordinate); \
op->Add(extra); \
AddImageOperands(op.get(), image_operands, operands); \
return AddCode(std::move(op)); \
code->Reserve(7 + operands.size()); \
return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate << extra \
<< image_operands << operands << EndOp{}; \
}
#define DEFINE_IMAGE_EXTRA_EXP_OP(opcode) \
Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \
spv::ImageOperandsMask image_operands, std::span<const Id> operands) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(sampled_image); \
op->Add(coordinate); \
op->Add(extra); \
op->Add(static_cast<u32>(image_operands)); \
op->Add(operands); \
return AddCode(std::move(op)); \
code->Reserve(8 + operands.size()); \
return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate << extra \
<< image_operands << operands << EndOp{}; \
}
#define DEFINE_IMAGE_QUERY_OP(opcode) \
Id Module::opcode(Id result_type, Id image) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(image); \
return AddCode(std::move(op)); \
code->Reserve(5); \
return *code << OpId{spv::Op::opcode, result_type} << image << EndOp{}; \
}
#define DEFINE_IMAGE_QUERY_BIN_OP(opcode) \
Id Module::opcode(Id result_type, Id image, Id extra) { \
auto op{std::make_unique<Op>(spv::Op::opcode, bound++, result_type)}; \
op->Add(image); \
op->Add(extra); \
return AddCode(std::move(op)); \
code->Reserve(5); \
return *code << OpId{spv::Op::OpDecorate, result_type} << image << extra << EndOp{}; \
}
DEFINE_IMAGE_OP(OpImageSampleImplicitLod)
@ -98,27 +77,22 @@ DEFINE_IMAGE_QUERY_OP(OpImageQueryLevels)
DEFINE_IMAGE_QUERY_OP(OpImageQuerySamples)
Id Module::OpSampledImage(Id result_type, Id image, Id sampler) {
auto op{std::make_unique<Op>(spv::Op::OpSampledImage, bound++, result_type)};
op->Add(image);
op->Add(sampler);
return AddCode(std::move(op));
code->Reserve(5);
return *code << OpId{spv::Op::OpSampledImage, result_type} << image << sampler << EndOp{};
}
Id Module::OpImageWrite(Id image, Id coordinate, Id texel,
std::optional<spv::ImageOperandsMask> image_operands,
std::span<const Id> operands) {
auto op{std::make_unique<Op>(spv::Op::OpImageWrite)};
op->Add(image);
op->Add(coordinate);
op->Add(texel);
AddImageOperands(op.get(), image_operands, operands);
return AddCode(std::move(op));
assert(image_operands.has_value() != operands.empty());
code->Reserve(5 + operands.size());
return *code << spv::Op::OpImageWrite << image << coordinate << texel << image_operands
<< operands << EndOp{};
}
Id Module::OpImage(Id result_type, Id sampled_image) {
auto op{std::make_unique<Op>(spv::Op::OpImage, bound++, result_type)};
op->Add(sampled_image);
return AddCode(std::move(op));
code->Reserve(4);
return *code << OpId{spv::Op::OpImage, result_type} << sampled_image << EndOp{};
}
} // namespace Sirit

View file

@ -4,68 +4,62 @@
* 3-Clause BSD License
*/
#include <memory>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h"
#include "stream.h"
namespace Sirit {
#define DEFINE_UNARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand); \
return AddCode(std::move(op)); \
#define DEFINE_UNARY(opcode) \
Id Module::opcode(Id result_type, Id operand) { \
code->Reserve(4); \
return *code << OpId{spv::Op::opcode, result_type} << operand << EndOp{}; \
}
#define DEFINE_BINARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand_1); \
op->Add(operand_2); \
return AddCode(std::move(op)); \
#define DEFINE_BINARY(opcode) \
Id Module::opcode(Id result_type, Id operand_1, Id operand_2) { \
code->Reserve(5); \
return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << EndOp{}; \
}
#define DEFINE_TRINARY(funcname, opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \
op->Add(operand_1); \
op->Add(operand_2); \
op->Add(operand_3); \
return AddCode(std::move(op)); \
#define DEFINE_TRINARY(opcode) \
Id Module::opcode(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
code->Reserve(5); \
return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << operand_3 \