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;