From 0b9ee36247758920e51811cbde06f6b24f969eb1 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 1 Aug 2020 01:50:01 -0300 Subject: [PATCH] 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. --- include/sirit/sirit.h | 79 +++++------- src/CMakeLists.txt | 9 -- src/instructions/annotation.cpp | 26 ++-- src/instructions/arithmetic.cpp | 25 +--- src/instructions/atomic.cpp | 138 ++++++++------------- src/instructions/barrier.cpp | 17 +-- src/instructions/bit.cpp | 81 +++++-------- src/instructions/constant.cpp | 32 ++--- src/instructions/conversion.cpp | 10 +- src/instructions/debug.cpp | 39 +++--- src/instructions/extension.cpp | 15 ++- src/instructions/flow.cpp | 63 +++++----- src/instructions/function.cpp | 22 ++-- src/instructions/group.cpp | 38 +++--- src/instructions/image.cpp | 82 +++++-------- src/instructions/logical.cpp | 100 ++++++++-------- src/instructions/memory.cpp | 81 +++++-------- src/instructions/misc.cpp | 12 +- src/instructions/type.cpp | 109 +++++++---------- src/literal_number.cpp | 37 ------ src/literal_number.h | 43 ------- src/literal_string.cpp | 33 ----- src/literal_string.h | 30 ----- src/op.cpp | 135 --------------------- src/op.h | 63 ---------- src/operand.cpp | 16 --- src/operand.h | 36 ------ src/sirit.cpp | 158 +++++++++++------------- src/stream.cpp | 51 -------- src/stream.h | 206 ++++++++++++++++++++++++++++++-- tests/main.cpp | 15 ++- 31 files changed, 651 insertions(+), 1150 deletions(-) delete mode 100644 src/literal_number.cpp delete mode 100644 src/literal_number.h delete mode 100644 src/literal_string.cpp delete mode 100644 src/literal_string.h delete mode 100644 src/op.cpp delete mode 100644 src/op.h delete mode 100644 src/operand.cpp delete mode 100644 src/operand.h diff --git a/include/sirit/sirit.h b/include/sirit/sirit.h index 3d47d93..dd45d4f 100644 --- a/include/sirit/sirit.h +++ b/include/sirit/sirit.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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; -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 interfaces = {}); /// Adds an entry point. template - 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{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 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 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 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 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); - - Id AddCode(spv::Op opcode, std::optional id = {}); - - Id AddDeclaration(std::unique_ptr op); - - void AddAnnotation(std::unique_ptr op); - Id GetGLSLstd450(); std::uint32_t version{}; - std::uint32_t bound{1}; + std::uint32_t bound{}; std::unordered_set extensions; std::unordered_set capabilities; - std::unordered_set> ext_inst_import; - std::unique_ptr glsl_std_450; + std::optional glsl_std_450; spv::AddressingModel addressing_model{spv::AddressingModel::Logical}; spv::MemoryModel memory_model{spv::MemoryModel::GLSL450}; - std::vector> entry_points; - std::vector> execution_modes; - std::vector> debug; - std::vector> annotations; - std::vector> declarations; - - std::vector global_variables; - - std::vector code; - - std::vector> code_store; + std::unique_ptr ext_inst_imports; + std::unique_ptr entry_points; + std::unique_ptr execution_modes; + std::unique_ptr debug; + std::unique_ptr annotations; + std::unique_ptr declarations; + std::unique_ptr global_variables; + std::unique_ptr code; + }; } // namespace Sirit diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d62c7c..64b50b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/instructions/annotation.cpp b/src/instructions/annotation.cpp index cbe4343..e3524bb 100644 --- a/src/instructions/annotation.cpp +++ b/src/instructions/annotation.cpp @@ -4,32 +4,24 @@ * 3-Clause BSD License */ -#include -#include -#include "common_types.h" -#include "op.h" +#include + #include "sirit/sirit.h" +#include "stream.h" + namespace Sirit { Id Module::Decorate(Id target, spv::Decoration decoration, std::span literals) { - auto op{std::make_unique(spv::Op::OpDecorate)}; - op->Add(target); - op->Add(static_cast(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 literals) { - auto op{std::make_unique(spv::Op::OpMemberDecorate)}; - op->Add(structure_type); - op->Add(member); - op->Add(static_cast(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 diff --git a/src/instructions/arithmetic.cpp b/src/instructions/arithmetic.cpp index 4cc1cf0..4fa8057 100644 --- a/src/instructions/arithmetic.cpp +++ b/src/instructions/arithmetic.cpp @@ -4,35 +4,22 @@ * 3-Clause BSD License */ -#include -#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(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(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(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) diff --git a/src/instructions/atomic.cpp b/src/instructions/atomic.cpp index 146a2a6..cee8849 100644 --- a/src/instructions/atomic.cpp +++ b/src/instructions/atomic.cpp @@ -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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 diff --git a/src/instructions/barrier.cpp b/src/instructions/barrier.cpp index da74bf5..646b5cf 100644 --- a/src/instructions/barrier.cpp +++ b/src/instructions/barrier.cpp @@ -4,25 +4,20 @@ * 3-Clause BSD License */ -#include -#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(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(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 diff --git a/src/instructions/bit.cpp b/src/instructions/bit.cpp index 25f4eff..c860613 100644 --- a/src/instructions/bit.cpp +++ b/src/instructions/bit.cpp @@ -4,96 +4,73 @@ * 3-Clause BSD License */ -#include -#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(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(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(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(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(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(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(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(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(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(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(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(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 diff --git a/src/instructions/constant.cpp b/src/instructions/constant.cpp index 25b0fa5..612049c 100644 --- a/src/instructions/constant.cpp +++ b/src/instructions/constant.cpp @@ -5,42 +5,44 @@ */ #include -#include "op.h" + #include "sirit/sirit.h" +#include "stream.h" + namespace Sirit { Id Module::ConstantTrue(Id result_type) { - return AddDeclaration(std::make_unique(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(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(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 constituents) { - auto op{std::make_unique(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(spv::Op::OpConstantSampler, bound, result_type)}; - op->Add(static_cast(addressing_mode)); - op->Add(normalized ? 1 : 0); - op->Add(static_cast(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(spv::Op::OpConstantNull, bound, result_type)); + declarations->Reserve(3); + return *declarations << OpId{spv::Op::OpConstantNull, result_type} << EndOp{}; } } // namespace Sirit diff --git a/src/instructions/conversion.cpp b/src/instructions/conversion.cpp index 57d57c9..0b4e2c8 100644 --- a/src/instructions/conversion.cpp +++ b/src/instructions/conversion.cpp @@ -4,18 +4,16 @@ * 3-Clause BSD License */ -#include -#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(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) diff --git a/src/instructions/debug.cpp b/src/instructions/debug.cpp index abbf02a..1ca3462 100644 --- a/src/instructions/debug.cpp +++ b/src/instructions/debug.cpp @@ -4,44 +4,33 @@ * 3-Clause BSD License */ -#include -#include -#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(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(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(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(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 diff --git a/src/instructions/extension.cpp b/src/instructions/extension.cpp index 332d972..9f7aa43 100644 --- a/src/instructions/extension.cpp +++ b/src/instructions/extension.cpp @@ -4,20 +4,18 @@ * 3-Clause BSD License */ -#include #include -#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 operands) { - auto op{std::make_unique(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 diff --git a/src/instructions/flow.cpp b/src/instructions/flow.cpp index 2520e6c..e40800c 100644 --- a/src/instructions/flow.cpp +++ b/src/instructions/flow.cpp @@ -5,79 +5,70 @@ */ #include -#include -#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 literals) { - auto op{std::make_unique(spv::Op::OpLoopMerge)}; - op->Add(merge_block); - op->Add(continue_target); - op->Add(static_cast(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(spv::Op::OpSelectionMerge)}; - op->Add(merge_block); - op->Add(static_cast(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(spv::Op::OpLabel, bound++)).get(); + return Id{++bound}; } Id Module::OpBranch(Id target_label) { - auto op{std::make_unique(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(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 literals, std::span labels) { - const std::size_t size = literals.size(); assert(literals.size() == labels.size()); - auto op{std::make_unique(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(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(spv::Op::OpKill)); + code->Reserve(1); + return *code << spv::Op::OpKill << EndOp{}; } } // namespace Sirit diff --git a/src/instructions/function.cpp b/src/instructions/function.cpp index f5982e8..ece60e6 100644 --- a/src/instructions/function.cpp +++ b/src/instructions/function.cpp @@ -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(spv::Op::OpFunction, bound++, result_type)}; - op->Add(static_cast(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 arguments) { - auto op{std::make_unique(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 diff --git a/src/instructions/group.cpp b/src/instructions/group.cpp index aba6422..605a17f 100644 --- a/src/instructions/group.cpp +++ b/src/instructions/group.cpp @@ -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(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(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(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(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(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(spv::Op::OpGroupNonUniformShuffleXor, bound++, result_type); - op->Add(static_cast(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 diff --git a/src/instructions/image.cpp b/src/instructions/image.cpp index 7db8f1c..292ae8b 100644 --- a/src/instructions/image.cpp +++ b/src/instructions/image.cpp @@ -4,79 +4,58 @@ * 3-Clause BSD License */ -#include "common_types.h" -#include "op.h" +#include + #include "sirit/sirit.h" -namespace Sirit { +#include "stream.h" -static void AddImageOperands(Op* op, std::optional image_operands, - std::span operands) { - if (!image_operands) - return; - op->Add(static_cast(*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 image_operands, \ std::span operands) { \ - auto op{std::make_unique(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 operands) { \ - auto op{std::make_unique(spv::Op::opcode, bound++, result_type)}; \ - op->Add(sampled_image); \ - op->Add(coordinate); \ - op->Add(static_cast(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 image_operands, \ std::span operands) { \ - auto op{std::make_unique(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 operands) { \ - auto op{std::make_unique(spv::Op::opcode, bound++, result_type)}; \ - op->Add(sampled_image); \ - op->Add(coordinate); \ - op->Add(extra); \ - op->Add(static_cast(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(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(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(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 image_operands, std::span operands) { - auto op{std::make_unique(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(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 diff --git a/src/instructions/logical.cpp b/src/instructions/logical.cpp index d88d664..281ab14 100644 --- a/src/instructions/logical.cpp +++ b/src/instructions/logical.cpp @@ -4,68 +4,62 @@ * 3-Clause BSD License */ -#include -#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(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(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(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 \ + << EndOp{}; \ } -DEFINE_UNARY(OpAny, spv::Op::OpAny) -DEFINE_UNARY(OpAll, spv::Op::OpAll) -DEFINE_UNARY(OpIsNan, spv::Op::OpIsNan) -DEFINE_UNARY(OpIsInf, spv::Op::OpIsInf) -DEFINE_BINARY(OpLogicalEqual, spv::Op::OpLogicalEqual) -DEFINE_BINARY(OpLogicalNotEqual, spv::Op::OpLogicalNotEqual) -DEFINE_BINARY(OpLogicalOr, spv::Op::OpLogicalOr) -DEFINE_BINARY(OpLogicalAnd, spv::Op::OpLogicalAnd) -DEFINE_UNARY(OpLogicalNot, spv::Op::OpLogicalNot) -DEFINE_TRINARY(OpSelect, spv::Op::OpSelect) -DEFINE_BINARY(OpIEqual, spv::Op::OpIEqual) -DEFINE_BINARY(OpINotEqual, spv::Op::OpINotEqual) -DEFINE_BINARY(OpUGreaterThan, spv::Op::OpUGreaterThan) -DEFINE_BINARY(OpSGreaterThan, spv::Op::OpSGreaterThan) -DEFINE_BINARY(OpUGreaterThanEqual, spv::Op::OpUGreaterThanEqual) -DEFINE_BINARY(OpSGreaterThanEqual, spv::Op::OpSGreaterThanEqual) -DEFINE_BINARY(OpULessThan, spv::Op::OpULessThan) -DEFINE_BINARY(OpSLessThan, spv::Op::OpSLessThan) -DEFINE_BINARY(OpULessThanEqual, spv::Op::OpULessThanEqual) -DEFINE_BINARY(OpSLessThanEqual, spv::Op::OpSLessThanEqual) -DEFINE_BINARY(OpFOrdEqual, spv::Op::OpFOrdEqual) -DEFINE_BINARY(OpFUnordEqual, spv::Op::OpFUnordEqual) -DEFINE_BINARY(OpFOrdNotEqual, spv::Op::OpFOrdNotEqual) -DEFINE_BINARY(OpFUnordNotEqual, spv::Op::OpFUnordNotEqual) -DEFINE_BINARY(OpFOrdLessThan, spv::Op::OpFOrdLessThan) -DEFINE_BINARY(OpFUnordLessThan, spv::Op::OpFUnordLessThan) -DEFINE_BINARY(OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThan) -DEFINE_BINARY(OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThan) -DEFINE_BINARY(OpFOrdLessThanEqual, spv::Op::OpFOrdLessThanEqual) -DEFINE_BINARY(OpFUnordLessThanEqual, spv::Op::OpFUnordLessThanEqual) -DEFINE_BINARY(OpFOrdGreaterThanEqual, spv::Op::OpFOrdGreaterThanEqual) -DEFINE_BINARY(OpFUnordGreaterThanEqual, spv::Op::OpFUnordGreaterThanEqual) +DEFINE_UNARY(OpAny) +DEFINE_UNARY(OpAll) +DEFINE_UNARY(OpIsNan) +DEFINE_UNARY(OpIsInf) +DEFINE_BINARY(OpLogicalEqual) +DEFINE_BINARY(OpLogicalNotEqual) +DEFINE_BINARY(OpLogicalOr) +DEFINE_BINARY(OpLogicalAnd) +DEFINE_UNARY(OpLogicalNot) +DEFINE_TRINARY(OpSelect) +DEFINE_BINARY(OpIEqual) +DEFINE_BINARY(OpINotEqual) +DEFINE_BINARY(OpUGreaterThan) +DEFINE_BINARY(OpSGreaterThan) +DEFINE_BINARY(OpUGreaterThanEqual) +DEFINE_BINARY(OpSGreaterThanEqual) +DEFINE_BINARY(OpULessThan) +DEFINE_BINARY(OpSLessThan) +DEFINE_BINARY(OpULessThanEqual) +DEFINE_BINARY(OpSLessThanEqual) +DEFINE_BINARY(OpFOrdEqual) +DEFINE_BINARY(OpFUnordEqual) +DEFINE_BINARY(OpFOrdNotEqual) +DEFINE_BINARY(OpFUnordNotEqual) +DEFINE_BINARY(OpFOrdLessThan) +DEFINE_BINARY(OpFUnordLessThan) +DEFINE_BINARY(OpFOrdGreaterThan) +DEFINE_BINARY(OpFUnordGreaterThan) +DEFINE_BINARY(OpFOrdLessThanEqual) +DEFINE_BINARY(OpFUnordLessThanEqual) +DEFINE_BINARY(OpFOrdGreaterThanEqual) +DEFINE_BINARY(OpFUnordGreaterThanEqual) } // namespace Sirit diff --git a/src/instructions/memory.cpp b/src/instructions/memory.cpp index 8b3a159..a542e9f 100644 --- a/src/instructions/memory.cpp +++ b/src/instructions/memory.cpp @@ -5,91 +5,64 @@ */ #include -#include "op.h" + #include "sirit/sirit.h" +#include "stream.h" + namespace Sirit { -Id Module::OpVariable(Id result_type, spv::StorageClass storage_class, Id initializer) { - auto op{std::make_unique(spv::Op::OpVariable, bound++, result_type)}; - op->Add(static_cast(storage_class)); - if (initializer) { - op->Add(initializer); - } - return code_store.emplace_back(std::move(op)).get(); -} - Id Module::OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample) { - auto op{std::make_unique(spv::Op::OpImageTexelPointer, bound++, result_type)}; - op->Add(image); - op->Add(coordinate); - op->Add(sample); - return AddCode(std::move(op)); + code->Reserve(6); + return *code << OpId{spv::Op::OpImageTexelPointer, result_type} << image << coordinate << sample + << EndOp{}; } Id Module::OpLoad(Id result_type, Id pointer, std::optional memory_access) { - auto op{std::make_unique(spv::Op::OpLoad, bound++, result_type)}; - op->Add(pointer); - if (memory_access) { - op->Add(static_cast(*memory_access)); - } - return AddCode(std::move(op)); + code->Reserve(5); + return *code << OpId{spv::Op::OpLoad, result_type} << pointer << memory_access << EndOp{}; } Id Module::OpStore(Id pointer, Id object, std::optional memory_access) { - auto op{std::make_unique(spv::Op::OpStore)}; - op->Add(pointer); - op->Add(object); - if (memory_access) { - op->Add(static_cast(*memory_access)); - } - return AddCode(std::move(op)); + code->Reserve(4); + return *code << spv::Op::OpStore << pointer << object << memory_access << EndOp{}; } Id Module::OpAccessChain(Id result_type, Id base, std::span indexes) { - assert(indexes.size() > 0); - auto op{std::make_unique(spv::Op::OpAccessChain, bound++, result_type)}; - op->Add(base); - op->Add(indexes); - return AddCode(std::move(op)); + assert(!indexes.empty()); + code->Reserve(4 + indexes.size()); + return *code << OpId{spv::Op::OpAccessChain, result_type} << base << indexes << EndOp{}; } Id Module::OpVectorExtractDynamic(Id result_type, Id vector, Id index) { - auto op{std::make_unique(spv::Op::OpVectorExtractDynamic, bound++, result_type)}; - op->Add(vector); - op->Add(index); - return AddCode(std::move(op)); + code->Reserve(5); + return *code << OpId{spv::Op::OpVectorExtractDynamic, result_type} << vector << index + << EndOp{}; } Id Module::OpVectorInsertDynamic(Id result_type, Id vector, Id component, Id index) { - auto op{std::make_unique(spv::Op::OpVectorInsertDynamic, bound++, result_type)}; - op->Add(vector); - op->Add(component); - op->Add(index); - return AddCode(std::move(op)); + code->Reserve(6); + return *code << OpId{spv::Op::OpVectorInsertDynamic, result_type} << vector << component + << index << EndOp{}; } Id Module::OpCompositeInsert(Id result_type, Id object, Id composite, std::span indexes) { - auto op{std::make_unique(spv::Op::OpCompositeInsert, bound++, result_type)}; - op->Add(object); - op->Add(composite); - op->Add(indexes); - return AddCode(std::move(op)); + code->Reserve(5 + indexes.size()); + return *code << OpId{spv::Op::OpCompositeInsert, result_type} << object << composite << indexes + << EndOp{}; } Id Module::OpCompositeExtract(Id result_type, Id composite, std::span indexes) { - auto op{std::make_unique(spv::Op::OpCompositeExtract, bound++, result_type)}; - op->Add(composite); - op->Add(indexes); - return AddCode(std::move(op)); + code->Reserve(4 + indexes.size()); + return *code << OpId{spv::Op::OpCompositeExtract, result_type} << composite << indexes + << EndOp{}; } Id Module::OpCompositeConstruct(Id result_type, std::span ids) { assert(ids.size() >= 1); - auto op{std::make_unique(spv::Op::OpCompositeConstruct, bound++, result_type)}; - op->Add(ids); - return AddCode(std::move(op)); + code->Reserve(3 + ids.size()); + return *code << OpId{spv::Op::OpCompositeConstruct, result_type} << ids << EndOp{}; } } // namespace Sirit diff --git a/src/instructions/misc.cpp b/src/instructions/misc.cpp index b589090..2f3b07d 100644 --- a/src/instructions/misc.cpp +++ b/src/instructions/misc.cpp @@ -4,21 +4,25 @@ * 3-Clause BSD License */ -#include "op.h" #include "sirit/sirit.h" +#include "stream.h" + namespace Sirit { Id Module::OpUndef(Id result_type) { - return AddCode(std::make_unique(spv::Op::OpUndef, bound++, result_type)); + code->Reserve(3); + return *code << OpId{spv::Op::OpUndef, result_type} << EndOp{}; } Id Module::OpEmitVertex() { - return AddCode(std::make_unique(spv::Op::OpEmitVertex)); + code->Reserve(1); + return *code << OpId{spv::Op::OpEmitVertex} << EndOp{}; } Id Module::OpEndPrimitive() { - return AddCode(std::make_unique(spv::Op::OpEndPrimitive)); + code->Reserve(1); + return *code << OpId{spv::Op::OpEndPrimitive} << EndOp{}; } } // namespace Sirit diff --git a/src/instructions/type.cpp b/src/instructions/type.cpp index e302cd2..c3d04a0 100644 --- a/src/instructions/type.cpp +++ b/src/instructions/type.cpp @@ -5,137 +5,118 @@ */ #include -#include #include -#include "op.h" #include "sirit/sirit.h" +#include "stream.h" + namespace Sirit { Id Module::TypeVoid() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeVoid, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeVoid} << EndOp{}; } Id Module::TypeBool() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeBool, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeBool} << EndOp{}; } Id Module::TypeInt(int width, bool is_signed) { - auto op{std::make_unique(spv::Op::OpTypeInt, bound)}; - op->Add(width); - op->Add(is_signed ? 1 : 0); - return AddDeclaration(std::move(op)); + declarations->Reserve(4); + return *declarations << OpId{spv::Op::OpTypeInt} << width << is_signed << EndOp{}; } Id Module::TypeFloat(int width) { - auto op{std::make_unique(spv::Op::OpTypeFloat, bound)}; - op->Add(width); - return AddDeclaration(std::move(op)); + declarations->Reserve(3); + return *declarations << OpId{spv::Op::OpTypeFloat} << width << EndOp{}; } Id Module::TypeVector(Id component_type, int component_count) { assert(component_count >= 2); - auto op{std::make_unique(spv::Op::OpTypeVector, bound)}; - op->Add(component_type); - op->Add(component_count); - return AddDeclaration(std::move(op)); + declarations->Reserve(4); + return *declarations << OpId{spv::Op::OpTypeVector} << component_type << component_count + << EndOp{}; } Id Module::TypeMatrix(Id column_type, int column_count) { assert(column_count >= 2); - auto op{std::make_unique(spv::Op::OpTypeMatrix, bound)}; - op->Add(column_type); - op->Add(column_count); - return AddDeclaration(std::move(op)); + declarations->Reserve(4); + return *declarations << OpId{spv::Op::OpTypeMatrix} << column_type << column_count << EndOp{}; } Id Module::TypeImage(Id sampled_type, spv::Dim dim, int depth, bool arrayed, bool ms, int sampled, spv::ImageFormat image_format, std::optional access_qualifier) { - auto op{std::make_unique(spv::Op::OpTypeImage, bound)}; - op->Add(sampled_type); - op->Add(static_cast(dim)); - op->Add(depth); - op->Add(arrayed ? 1 : 0); - op->Add(ms ? 1 : 0); - op->Add(sampled); - op->Add(static_cast(image_format)); - if (access_qualifier.has_value()) { - op->Add(static_cast(access_qualifier.value())); - } - return AddDeclaration(std::move(op)); + declarations->Reserve(10); + return *declarations << OpId{spv::Op::OpTypeImage} << sampled_type << dim << depth << arrayed + << ms << sampled << image_format << access_qualifier << EndOp{}; } Id Module::TypeSampler() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeSampler, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeSampler} << EndOp{}; } Id Module::TypeSampledImage(Id image_type) { - auto op{std::make_unique(spv::Op::OpTypeSampledImage, bound)}; - op->Add(image_type); - return AddDeclaration(std::move(op)); + declarations->Reserve(3); + return *declarations << OpId{spv::Op::OpTypeSampledImage} << image_type << EndOp{}; } Id Module::TypeArray(Id element_type, Id length) { - auto op{std::make_unique(spv::Op::OpTypeArray, bound)}; - op->Add(element_type); - op->Add(length); - return AddDeclaration(std::move(op)); + declarations->Reserve(4); + return *declarations << OpId{spv::Op::OpTypeArray} << element_type << length << EndOp{}; } Id Module::TypeRuntimeArray(Id element_type) { - auto op{std::make_unique(spv::Op::OpTypeRuntimeArray, bound)}; - op->Add(element_type); - return AddDeclaration(std::move(op)); + declarations->Reserve(3); + return *declarations << OpId{spv::Op::OpTypeRuntimeArray} << element_type << EndOp{}; } Id Module::TypeStruct(std::span members) { - auto op{std::make_unique(spv::Op::OpTypeStruct, bound)}; - op->Add(members); - return AddDeclaration(std::move(op)); + declarations->Reserve(2 + members.size()); + return *declarations << OpId{spv::Op::OpTypeStruct} << members << EndOp{}; } -Id Module::TypeOpaque(std::string name) { - auto op{std::make_unique(spv::Op::OpTypeOpaque, bound)}; - op->Add(std::move(name)); - return AddDeclaration(std::move(op)); +Id Module::TypeOpaque(std::string_view name) { + declarations->Reserve(3 + WordsInString(name)); + return *declarations << OpId{spv::Op::OpTypeOpaque} << name << EndOp{}; } Id Module::TypePointer(spv::StorageClass storage_class, Id type) { - auto op{std::make_unique(spv::Op::OpTypePointer, bound)}; - op->Add(static_cast(storage_class)); - op->Add(type); - return AddDeclaration(std::move(op)); + declarations->Reserve(4); + return *declarations << OpId{spv::Op::OpTypePointer} << storage_class << type << EndOp{}; } Id Module::TypeFunction(Id return_type, std::span arguments) { - auto op{std::make_unique(spv::Op::OpTypeFunction, bound)}; - op->Add(return_type); - op->Add(arguments); - return AddDeclaration(std::move(op)); + declarations->Reserve(3 + arguments.size()); + return *declarations << OpId{spv::Op::OpTypeFunction} << return_type << arguments << EndOp{}; } Id Module::TypeEvent() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeEvent, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeEvent} << EndOp{}; } Id Module::TypeDeviceEvent() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeDeviceEvent, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeDeviceEvent} << EndOp{}; } Id Module::TypeReserveId() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeReserveId, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeReserveId} << EndOp{}; } Id Module::TypeQueue() { - return AddDeclaration(std::make_unique(spv::Op::OpTypeQueue, bound)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypeQueue} << EndOp{}; } Id Module::TypePipe(spv::AccessQualifier access_qualifier) { - auto op{std::make_unique(spv::Op::OpTypePipe, bound)}; - op->Add(static_cast(access_qualifier)); - return AddDeclaration(std::move(op)); + declarations->Reserve(2); + return *declarations << OpId{spv::Op::OpTypePipe} << access_qualifier << EndOp{}; } } // namespace Sirit diff --git a/src/literal_number.cpp b/src/literal_number.cpp deleted file mode 100644 index a4c436e..0000000 --- a/src/literal_number.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#include -#include "literal_number.h" - -namespace Sirit { - -LiteralNumber::LiteralNumber(u64 raw_, bool is_32_) - : Operand{OperandType::Number}, raw{raw_}, is_32{is_32_} {} - -LiteralNumber::~LiteralNumber() = default; - -void LiteralNumber::Fetch(Stream& stream) const { - if (is_32) { - stream.Write(static_cast(raw)); - } else { - stream.Write(raw); - } -} - -std::size_t LiteralNumber::GetWordCount() const noexcept { - return is_32 ? 1 : 2; -} - -bool LiteralNumber::Equal(const Operand& other) const noexcept { - if (!EqualType(other)) { - return false; - } - const auto& o{static_cast(other)}; - return o.raw == raw && o.is_32 == is_32; -} - -} // namespace Sirit diff --git a/src/literal_number.h b/src/literal_number.h deleted file mode 100644 index 46d19b0..0000000 --- a/src/literal_number.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#pragma once - -#include -#include -#include - -#include "operand.h" -#include "stream.h" - -namespace Sirit { - -class LiteralNumber final : public Operand { -public: - explicit LiteralNumber(u64 raw, bool is_32); - ~LiteralNumber() override; - - void Fetch(Stream& stream) const override; - - std::size_t GetWordCount() const noexcept override; - - bool Equal(const Operand& other) const noexcept override; - - template - static std::unique_ptr Create(T value) { - static_assert(sizeof(T) == 4 || sizeof(T) == 8); - - u64 raw{}; - std::memcpy(&raw, &value, sizeof(T)); - return std::make_unique(raw, sizeof(T) == 4); - } - -private: - u64 raw{}; - bool is_32{}; -}; - -} // namespace Sirit diff --git a/src/literal_string.cpp b/src/literal_string.cpp deleted file mode 100644 index 58aa40f..0000000 --- a/src/literal_string.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#include -#include "common_types.h" -#include "literal_string.h" - -namespace Sirit { - -LiteralString::LiteralString(std::string string_) - : Operand{OperandType::String}, string{std::move(string_)} {} - -LiteralString::~LiteralString() = default; - -void LiteralString::Fetch(Stream& stream) const { - stream.Write(string); -} - -std::size_t LiteralString::GetWordCount() const noexcept { - return string.size() / 4 + 1; -} - -bool LiteralString::Equal(const Operand& other) const noexcept { - if (!EqualType(other)) { - return false; - } - return static_cast(other).string == string; -} - -} // namespace Sirit diff --git a/src/literal_string.h b/src/literal_string.h deleted file mode 100644 index 608ac53..0000000 --- a/src/literal_string.h +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#pragma once - -#include -#include "operand.h" -#include "stream.h" - -namespace Sirit { - -class LiteralString final : public Operand { -public: - LiteralString(std::string string); - ~LiteralString() override; - - void Fetch(Stream& stream) const override; - - std::size_t GetWordCount() const noexcept override; - - bool Equal(const Operand& other) const noexcept override; - -private: - std::string string; -}; - -} // namespace Sirit diff --git a/src/op.cpp b/src/op.cpp deleted file mode 100644 index d8d7ade..0000000 --- a/src/op.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#include -#include -#include - -#include "common_types.h" -#include "literal_number.h" -#include "literal_string.h" -#include "op.h" -#include "operand.h" - -namespace Sirit { - -Op::Op(spv::Op opcode_, std::optional id_, Id result_type_) - : Operand{OperandType::Op}, opcode{opcode_}, result_type{result_type_}, id{id_} {} - -Op::~Op() = default; - -void Op::Fetch(Stream& stream) const { - assert(id.has_value()); - stream.Write(id.value()); -} - -std::size_t Op::GetWordCount() const noexcept { - return 1; -} - -bool Op::Equal(const Operand& other) const noexcept { - if (!EqualType(other)) { - return false; - } - const auto& op = static_cast(other); - if (op.opcode == opcode && result_type == op.result_type && - operands.size() == op.operands.size()) { - for (std::size_t i = 0; i < operands.size(); i++) { - if (!operands[i]->Equal(*op.operands[i])) { - return false; - } - } - return true; - } - return false; -} - -void Op::Write(Stream& stream) const { - stream.Write(static_cast(opcode), CalculateTotalWords()); - - if (result_type) { - result_type->Fetch(stream); - } - if (id.has_value()) { - stream.Write(id.value()); - } - for (const auto* operand : operands) { - operand->Fetch(stream); - } -} - -void Op::Sink(std::unique_ptr operand) { - Add(static_cast(operand.get())); - operand_store.push_back(std::move(operand)); -} - -void Op::Add(const Literal& literal) { - Sink([&] { - switch (literal.index()) { - case 0: - return LiteralNumber::Create(std::get<0>(literal)); - case 1: - return LiteralNumber::Create(std::get<1>(literal)); - case 2: - return LiteralNumber::Create(std::get<2>(literal)); - case 3: - return LiteralNumber::Create(std::get<3>(literal)); - case 4: - return LiteralNumber::Create(std::get<4>(literal)); - case 5: - return LiteralNumber::Create(std::get<5>(literal)); - default: - // Invalid literal type - assert(0); - abort(); - } - }()); -} - -void Op::Add(std::span literals) { - for (const auto& literal : literals) { - Add(literal); - } -} - -void Op::Add(const Operand* operand) { - assert(operand); - operands.push_back(operand); -} - -void Op::Add(u32 integer) { - Sink(LiteralNumber::Create(integer)); -} - -void Op::Add(s32 integer) { - Sink(LiteralNumber::Create(integer)); -} - -void Op::Add(std::string string) { - Sink(std::make_unique(std::move(string))); -} - -void Op::Add(std::span ids) { - assert(std::all_of(ids.begin(), ids.end(), [](auto id_) { return id_; })); - operands.insert(operands.end(), ids.begin(), ids.end()); -} - -u16 Op::CalculateTotalWords() const noexcept { - std::size_t count = 1; - if (result_type) { - ++count; - } - if (id.has_value()) { - ++count; - } - for (const Operand* operand : operands) { - count += operand->GetWordCount(); - } - assert(count < std::numeric_limits::max()); - return static_cast(count); -} - -} // namespace Sirit diff --git a/src/op.h b/src/op.h deleted file mode 100644 index 276bfc9..0000000 --- a/src/op.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#pragma once - -#include -#include -#include - -#include "common_types.h" -#include "operand.h" -#include "sirit/sirit.h" -#include "stream.h" - -namespace Sirit { - -class Op final : public Operand { -public: - explicit Op(spv::Op opcode, std::optional id = {}, Id result_type = nullptr); - ~Op() override; - - void Fetch(Stream& stream) const override; - - std::size_t GetWordCount() const noexcept override; - - bool Equal(const Operand& other) const noexcept override; - - void Write(Stream& stream) const; - - void Sink(std::unique_ptr operand); - - void Add(const Literal& literal); - - void Add(std::span literals); - - void Add(const Operand* operand); - - void Add(u32 integer); - - void Add(s32 integer); - - void Add(std::string string); - - void Add(std::span ids); - -private: - u16 CalculateTotalWords() const noexcept; - - spv::Op opcode; - - Id result_type; - - std::optional id; - - std::vector operands; - - std::vector> operand_store; -}; - -} // namespace Sirit diff --git a/src/operand.cpp b/src/operand.cpp deleted file mode 100644 index 69e4409..0000000 --- a/src/operand.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#include -#include "operand.h" - -namespace Sirit { - -Operand::Operand(OperandType operand_type_) : operand_type{operand_type_} {} - -Operand::~Operand() = default; - -} // namespace Sirit diff --git a/src/operand.h b/src/operand.h deleted file mode 100644 index 90b11f1..0000000 --- a/src/operand.h +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#pragma once - -#include - -#include "stream.h" - -namespace Sirit { - -enum class OperandType { Invalid, Op, Number, String }; - -class Operand { -public: - explicit Operand(OperandType operand_type); - virtual ~Operand(); - - virtual void Fetch(Stream& stream) const = 0; - - virtual std::size_t GetWordCount() const noexcept = 0; - - virtual bool Equal(const Operand& other) const noexcept = 0; - - bool EqualType(const Operand& other) const noexcept { - return operand_type == other.operand_type; - } - -private: - OperandType operand_type; -}; - -} // namespace Sirit diff --git a/src/sirit.cpp b/src/sirit.cpp index c95634a..a2043ae 100644 --- a/src/sirit.cpp +++ b/src/sirit.cpp @@ -4,66 +4,66 @@ * 3-Clause BSD License */ -#include #include -#include "common_types.h" -#include "op.h" + #include "sirit/sirit.h" + +#include "common_types.h" #include "stream.h" namespace Sirit { -template -static void WriteSet(Stream& stream, const T& set) { - for (const auto& item : set) { - item->Write(stream); - } +constexpr u32 MakeWord0(spv::Op op, size_t word_count) { + return static_cast(op) | static_cast(word_count) << 16; } -Module::Module(u32 version_) : version{version_} {} +Module::Module(u32 version_) + : version{version_}, ext_inst_imports{std::make_unique(&bound)}, + entry_points{std::make_unique(&bound)}, + execution_modes{std::make_unique(&bound)}, debug{std::make_unique(&bound)}, + annotations{std::make_unique(&bound)}, declarations{std::make_unique( + &bound)}, + global_variables{std::make_unique(&bound)}, code{std::make_unique(&bound)} {} Module::~Module() = default; std::vector Module::Assemble() const { - std::vector bytes; - Stream stream{bytes}; + std::vector words = {spv::MagicNumber, version, GENERATOR_MAGIC_NUMBER, bound + 1, 0}; + const auto insert = [&words](std::span input) { + words.insert(words.end(), input.begin(), input.end()); + }; - stream.Write(spv::MagicNumber); - stream.Write(version); - stream.Write(GENERATOR_MAGIC_NUMBER); - stream.Write(bound); - stream.Write(static_cast(0)); - - for (const auto capability : capabilities) { - Op op(spv::Op::OpCapability); - op.Add(static_cast(capability)); - op.Write(stream); + words.reserve(words.size() + capabilities.size() * 2); + for (const spv::Capability capability : capabilities) { + insert(std::array{ + MakeWord0(spv::Op::OpCapability, 2), + static_cast(capability), + }); } - for (const auto& extension_name : extensions) { - Op op(spv::Op::OpExtension); - op.Add(extension_name); - op.Write(stream); + for (const std::string_view extension_name : extensions) { + size_t insert_index = words.size(); + words.resize(words.size() + WordsInString(extension_name)); + InsertStringView(words, insert_index, extension_name); } - if (glsl_std_450) { - glsl_std_450->Write(stream); - } + insert(ext_inst_imports->Words()); - Op memory_model_ref{spv::Op::OpMemoryModel}; - memory_model_ref.Add(static_cast(addressing_model)); - memory_model_ref.Add(static_cast(memory_model)); - memory_model_ref.Write(stream); + insert(std::array{ + MakeWord0(spv::Op::OpMemoryModel, 3), + static_cast(addressing_model), + static_cast(memory_model), + }); - WriteSet(stream, entry_points); - WriteSet(stream, execution_modes); - WriteSet(stream, debug); - WriteSet(stream, annotations); - WriteSet(stream, declarations); - WriteSet(stream, global_variables); - WriteSet(stream, code); + insert(entry_points->Words()); + insert(execution_modes->Words()); + insert(debug->Words()); + insert(annotations->Words()); + insert(declarations->Words()); + insert(global_variables->Words()); + insert(code->Words()); - return bytes; + return words; } void Module::AddExtension(std::string extension_name) { @@ -76,75 +76,51 @@ void Module::AddCapability(spv::Capability capability) { void Module::SetMemoryModel(spv::AddressingModel addressing_model_, spv::MemoryModel memory_model_) { - this->addressing_model = addressing_model_; - this->memory_model = memory_model_; + addressing_model = addressing_model_; + memory_model = memory_model_; } -void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string name, - std::span interfaces) { - auto op{std::make_unique(spv::Op::OpEntryPoint)}; - op->Add(static_cast(execution_model)); - op->Add(entry_point); - op->Add(std::move(name)); - op->Add(interfaces); - entry_points.push_back(std::move(op)); +void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, + std::string_view name, std::span interfaces) { + entry_points->Reserve(4 + WordsInString(name) + interfaces.size()); + *entry_points << spv::Op::OpEntryPoint << execution_model << entry_point << name << interfaces + << EndOp{}; } void Module::AddExecutionMode(Id entry_point, spv::ExecutionMode mode, std::span literals) { - auto op{std::make_unique(spv::Op::OpExecutionMode)}; - op->Add(entry_point); - op->Add(static_cast(mode)); - op->Add(literals); - execution_modes.push_back(std::move(op)); + execution_modes->Reserve(3 + literals.size()); + *execution_modes << spv::Op::OpExecutionMode << entry_point << mode << literals << EndOp{}; } Id Module::AddLabel(Id label) { - assert(label != nullptr); - return code.emplace_back(label); + assert(label.value != 0); + code->Reserve(2); + *code << MakeWord0(spv::Op::OpLabel, 2) << label.value; + return label; } -Id Module::AddLocalVariable(Id variable) { - assert(variable != nullptr); - return code.emplace_back(variable); +Id Module::AddLocalVariable(Id result_type, spv::StorageClass storage_class, + std::optional initializer) { + code->Reserve(5); + return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer + << EndOp{}; } -Id Module::AddGlobalVariable(Id variable) { - assert(variable); - return global_variables.emplace_back(variable); -} - -Id Module::AddCode(std::unique_ptr op) { - const Id id = code_store.emplace_back(std::move(op)).get(); - return code.emplace_back(id); -} - -Id Module::AddCode(spv::Op opcode, std::optional id) { - return AddCode(std::make_unique(opcode, id)); -} - -Id Module::AddDeclaration(std::unique_ptr op) { - const auto found = std::find_if(declarations.begin(), declarations.end(), - [&op](const auto& other) { return op->Equal(*other); }); - if (found != declarations.end()) { - return found->get(); - } - const auto id = op.get(); - declarations.push_back(std::move(op)); - ++bound; - return id; -} - -void Module::AddAnnotation(std::unique_ptr op) { - annotations.push_back(std::move(op)); +Id Module::AddGlobalVariable(Id result_type, spv::StorageClass storage_class, + std::optional initializer) { + code->Reserve(5); + return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer + << EndOp{}; } Id Module::GetGLSLstd450() { if (!glsl_std_450) { - glsl_std_450 = std::make_unique(spv::Op::OpExtInstImport, bound++); - glsl_std_450->Add("GLSL.std.450"); + ext_inst_imports->Reserve(3 + 4); + glsl_std_450 = *ext_inst_imports << OpId{spv::Op::OpExtInstImport} << "GLSL.std.450" + << EndOp{}; } - return glsl_std_450.get(); + return *glsl_std_450; } } // namespace Sirit diff --git a/src/stream.cpp b/src/stream.cpp index 32bafbd..e69de29 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,51 +0,0 @@ -/* This file is part of the sirit project. - * Copyright (c) 2019 sirit - * This software may be used and distributed according to the terms of the - * 3-Clause BSD License - */ - -#include "stream.h" - -namespace Sirit { - -Stream::Stream(std::vector& words_) : words{words_} {} - -Stream::~Stream() = default; - -void Stream::Write(std::string_view string) { - constexpr std::size_t word_size = 4; - const auto size = string.size(); - const auto read = [string, size](std::size_t offset) { - return offset < size ? static_cast(string[offset]) : u8(0); - }; - - words.reserve(words.size() + size / word_size + 1); - for (std::size_t i = 0; i < size; i += word_size) { - Write(read(i), read(i + 1), read(i + 2), read(i + 3)); - } - if (size % word_size == 0) { - Write(u32(0)); - } -} - -void Stream::Write(u64 value) { - const u32 dword[] = {static_cast(value), static_cast(value >> 32)}; - words.insert(std::begin(words), std::cbegin(dword), std::cend(dword)); -} - -void Stream::Write(u32 value) { - words.push_back(value); -} - -void Stream::Write(u16 first, u16 second) { - const u32 word = static_cast(first) | static_cast(second) << 16; - Write(word); -} - -void Stream::Write(u8 first, u8 second, u8 third, u8 fourth) { - const u32 word = static_cast(first) | static_cast(second) << 8 | - static_cast(third) << 16 | static_cast(fourth) << 24; - Write(word); -} - -} // namespace Sirit diff --git a/src/stream.h b/src/stream.h index b7ec872..265d6ef 100644 --- a/src/stream.h +++ b/src/stream.h @@ -6,29 +6,219 @@ #pragma once +#include +#include +#include +#include #include +#include +#include #include + +#include + #include "common_types.h" namespace Sirit { +class Declarations; + +struct OpId { + spv::Op opcode; + Id result_type; +}; + +struct EndOp {}; + +constexpr size_t WordsInString(std::string_view string) { + return string.size() / sizeof(u32); +} + +inline void InsertStringView(std::vector& words, size_t& insert_index, + std::string_view string) { + const size_t size = string.size(); + const auto read = [string, size](size_t offset) { + return offset < size ? static_cast(string[offset]) : u8(0); + }; + + for (size_t i = 0; i < size; i += sizeof(u32)) { + words[insert_index++] = read(i) | read(i + 1) << 8 | read(i + 2) << 16 | read(i + 3) << 24; + } + if (size % sizeof(u32) == 0) { + words[insert_index++] = 0; + } +} + class Stream { + friend Declarations; + public: - explicit Stream(std::vector& words); - ~Stream(); + explicit Stream(u32* bound_) : bound{bound_} {} - void Write(std::string_view string); + void Reserve(size_t num_words) { + if (insert_index + num_words <= words.size()) { + return; + } + words.resize(insert_index + num_words); + } - void Write(u64 value); + std::span Words() const noexcept { + return std::span(words.data(), insert_index); + } - void Write(u32 value); + Stream& operator<<(spv::Op op) { + op_index = insert_index; + words[insert_index++] = static_cast(op); + return *this; + } - void Write(u16 first, u16 second); + Stream& operator<<(OpId op) { + op_index = insert_index; + words[insert_index++] = static_cast(op.opcode); + if (op.result_type.value != 0) { + words[insert_index++] = op.result_type.value; + } + words[insert_index++] = ++*bound; + return *this; + } - void Write(u8 first, u8 second, u8 third, u8 fourth); + Id operator<<(EndOp) { + const size_t num_words = insert_index - op_index; + words[op_index] |= static_cast(num_words) << 16; + return Id{*bound}; + } + + Stream& operator<<(u32 value) { + words[insert_index++] = value; + return *this; + } + + Stream& operator<<(s32 value) { + return *this << static_cast(value); + } + + Stream& operator<<(u64 value) { + return *this << static_cast(value) << static_cast(value >> 32); + } + + Stream& operator<<(s64 value) { + return *this << static_cast(value); + } + + Stream& operator<<(float value) { + return *this << std::bit_cast(value); + } + + Stream& operator<<(double value) { + return *this << std::bit_cast(value); + } + + Stream& operator<<(bool value) { + return *this << static_cast(value ? 1 : 0); + } + + Stream& operator<<(Id value) { + return *this << value.value; + } + + Stream& operator<<(const Literal& literal) { + std::visit([this](auto value) { *this << value; }, literal); + return *this; + } + + Stream& operator<<(std::string_view string) { + InsertStringView(words, insert_index, string); + return *this; + } + + template + requires std::is_enum_v Stream& operator<<(T value) { + static_assert(sizeof(T) == sizeof(u32)); + return *this << static_cast(value); + } + + template + Stream& operator<<(std::optional value) { + if (value) { + *this << *value; + } + return *this; + } + + template + Stream& operator<<(std::span values) { + for (const auto& value : values) { + *this << value; + } + return *this; + } private: - std::vector& words; + u32* bound = nullptr; + std::vector words; + size_t insert_index = 0; + size_t op_index = 0; +}; + +class Declarations { +public: + explicit Declarations(u32* bound) : stream{bound} {} + + void Reserve(size_t num_words) { + return stream.Reserve(num_words); + } + + std::span Words() const noexcept { + return stream.Words(); + } + + template + Declarations& operator<<(const T& value) { + stream << value; + return *this; + } + + // Declarations without an id don't exist + Declarations& operator<<(spv::Op) = delete; + + Declarations& operator<<(OpId op) { + id_index = op.result_type.value != 0 ? 2 : 1; + stream << op; + return *this; + } + + Id operator<<(EndOp) { + const auto begin = stream.words.begin(); + std::vector declarations(begin + stream.op_index, begin + stream.insert_index); + + // Normalize result id for lookups + const u32 id = std::exchange(declarations[id_index], 0); + + const auto [entry, inserted] = existing_declarations.emplace(declarations, id); + if (inserted) { + return stream << EndOp{}; + } + // If the declaration already exists, undo the operation + stream.insert_index = stream.op_index; + --*stream.bound; + + return Id{entry->second}; + } + +private: + struct HashVector { + size_t operator()(const std::vector& vector) const noexcept { + size_t hash = std::hash{}(vector.size()); + for (const u32 value : vector) { + hash ^= std::hash{}(value); + } + return hash; + } + }; + + Stream stream; + std::unordered_map, u32, HashVector> existing_declarations; + size_t id_index = 0; }; } // namespace Sirit diff --git a/tests/main.cpp b/tests/main.cpp index 407dcd5..d119c25 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -7,6 +7,7 @@ #include #include #include + #include class MyModule : public Sirit::Module { @@ -31,9 +32,9 @@ public: const auto gl_per_vertex_ptr = Name(TypePointer(spv::StorageClass::Output, gl_per_vertex), "out_gl_PerVertex"); - const auto in_pos = Name(OpVariable(in_float4, spv::StorageClass::Input), "in_pos"); + const auto in_pos = Name(AddGlobalVariable(in_float4, spv::StorageClass::Input), "in_pos"); const auto per_vertex = - Name(OpVariable(gl_per_vertex_ptr, spv::StorageClass::Output), "per_vertex"); + Name(AddGlobalVariable(gl_per_vertex_ptr, spv::StorageClass::Output), "per_vertex"); Decorate(in_pos, spv::Decoration::Location, 0); Decorate(gl_per_vertex, spv::Decoration::Block); @@ -41,9 +42,6 @@ public: MemberDecorate(gl_per_vertex, 0, spv::Decoration::BuiltIn, static_cast(spv::BuiltIn::Position)); - AddGlobalVariable(in_pos); - AddGlobalVariable(per_vertex); - const auto main_func = Name( OpFunction(t_void, spv::FunctionControlMask::MaskNone, TypeFunction(t_void)), "main"); AddLabel(); @@ -57,8 +55,8 @@ public: auto tmp_position = OpUndef(float4); tmp_position = OpCompositeInsert(float4, pos_x, tmp_position, 0); tmp_position = OpCompositeInsert(float4, pos_y, tmp_position, 1); - tmp_position = OpCompositeInsert(float4, Constant(t_float, 0.f), tmp_position, 2); - tmp_position = OpCompositeInsert(float4, Constant(t_float, 1.f), tmp_position, 3); + tmp_position = OpCompositeInsert(float4, Constant(t_float, 0.0f), tmp_position, 2); + tmp_position = OpCompositeInsert(float4, Constant(t_float, 1.0f), tmp_position, 3); const auto gl_position = OpAccessChain(out_float4, per_vertex, Constant(t_uint, 0u)); OpStore(gl_position, tmp_position); @@ -123,7 +121,8 @@ static constexpr std::uint8_t expected_binary[] = { 0x1b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, +}; int main(int argc, char** argv) { MyModule module;