Stream SPIR-V instructions directly to a binary

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,68 +4,62 @@
* 3-Clause BSD License * 3-Clause BSD License
*/ */
#include <memory>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h" #include "sirit/sirit.h"
#include "stream.h"
namespace Sirit { namespace Sirit {
#define DEFINE_UNARY(funcname, opcode) \ #define DEFINE_UNARY(opcode) \
Id Module::funcname(Id result_type, Id operand) { \ Id Module::opcode(Id result_type, Id operand) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \ code->Reserve(4); \
op->Add(operand); \ return *code << OpId{spv::Op::opcode, result_type} << operand << EndOp{}; \
return AddCode(std::move(op)); \
} }
#define DEFINE_BINARY(funcname, opcode) \ #define DEFINE_BINARY(opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \ Id Module::opcode(Id result_type, Id operand_1, Id operand_2) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \ code->Reserve(5); \
op->Add(operand_1); \ return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << EndOp{}; \
op->Add(operand_2); \
return AddCode(std::move(op)); \
} }
#define DEFINE_TRINARY(funcname, opcode) \ #define DEFINE_TRINARY(opcode) \
Id Module::funcname(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \ Id Module::opcode(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
auto op{std::make_unique<Op>(opcode, bound++, result_type)}; \ code->Reserve(5); \
op->Add(operand_1); \ return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << operand_3 \
op->Add(operand_2); \ << EndOp{}; \
op->Add(operand_3); \
return AddCode(std::move(op)); \
} }
DEFINE_UNARY(OpAny, spv::Op::OpAny) DEFINE_UNARY(OpAny)
DEFINE_UNARY(OpAll, spv::Op::OpAll) DEFINE_UNARY(OpAll)
DEFINE_UNARY(OpIsNan, spv::Op::OpIsNan) DEFINE_UNARY(OpIsNan)
DEFINE_UNARY(OpIsInf, spv::Op::OpIsInf) DEFINE_UNARY(OpIsInf)
DEFINE_BINARY(OpLogicalEqual, spv::Op::OpLogicalEqual) DEFINE_BINARY(OpLogicalEqual)
DEFINE_BINARY(OpLogicalNotEqual, spv::Op::OpLogicalNotEqual) DEFINE_BINARY(OpLogicalNotEqual)
DEFINE_BINARY(OpLogicalOr, spv::Op::OpLogicalOr) DEFINE_BINARY(OpLogicalOr)
DEFINE_BINARY(OpLogicalAnd, spv::Op::OpLogicalAnd) DEFINE_BINARY(OpLogicalAnd)
DEFINE_UNARY(OpLogicalNot, spv::Op::OpLogicalNot) DEFINE_UNARY(OpLogicalNot)
DEFINE_TRINARY(OpSelect, spv::Op::OpSelect) DEFINE_TRINARY(OpSelect)
DEFINE_BINARY(OpIEqual, spv::Op::OpIEqual) DEFINE_BINARY(OpIEqual)
DEFINE_BINARY(OpINotEqual, spv::Op::OpINotEqual) DEFINE_BINARY(OpINotEqual)
DEFINE_BINARY(OpUGreaterThan, spv::Op::OpUGreaterThan) DEFINE_BINARY(OpUGreaterThan)
DEFINE_BINARY(OpSGreaterThan, spv::Op::OpSGreaterThan) DEFINE_BINARY(OpSGreaterThan)
DEFINE_BINARY(OpUGreaterThanEqual, spv::Op::OpUGreaterThanEqual) DEFINE_BINARY(OpUGreaterThanEqual)
DEFINE_BINARY(OpSGreaterThanEqual, spv::Op::OpSGreaterThanEqual) DEFINE_BINARY(OpSGreaterThanEqual)
DEFINE_BINARY(OpULessThan, spv::Op::OpULessThan) DEFINE_BINARY(OpULessThan)
DEFINE_BINARY(OpSLessThan, spv::Op::OpSLessThan) DEFINE_BINARY(OpSLessThan)
DEFINE_BINARY(OpULessThanEqual, spv::Op::OpULessThanEqual) DEFINE_BINARY(OpULessThanEqual)
DEFINE_BINARY(OpSLessThanEqual, spv::Op::OpSLessThanEqual) DEFINE_BINARY(OpSLessThanEqual)
DEFINE_BINARY(OpFOrdEqual, spv::Op::OpFOrdEqual) DEFINE_BINARY(OpFOrdEqual)
DEFINE_BINARY(OpFUnordEqual, spv::Op::OpFUnordEqual) DEFINE_BINARY(OpFUnordEqual)
DEFINE_BINARY(OpFOrdNotEqual, spv::Op::OpFOrdNotEqual) DEFINE_BINARY(OpFOrdNotEqual)
DEFINE_BINARY(OpFUnordNotEqual, spv::Op::OpFUnordNotEqual) DEFINE_BINARY(OpFUnordNotEqual)
DEFINE_BINARY(OpFOrdLessThan, spv::Op::OpFOrdLessThan) DEFINE_BINARY(OpFOrdLessThan)
DEFINE_BINARY(OpFUnordLessThan, spv::Op::OpFUnordLessThan) DEFINE_BINARY(OpFUnordLessThan)
DEFINE_BINARY(OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThan) DEFINE_BINARY(OpFOrdGreaterThan)
DEFINE_BINARY(OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThan) DEFINE_BINARY(OpFUnordGreaterThan)
DEFINE_BINARY(OpFOrdLessThanEqual, spv::Op::OpFOrdLessThanEqual) DEFINE_BINARY(OpFOrdLessThanEqual)
DEFINE_BINARY(OpFUnordLessThanEqual, spv::Op::OpFUnordLessThanEqual) DEFINE_BINARY(OpFUnordLessThanEqual)
DEFINE_BINARY(OpFOrdGreaterThanEqual, spv::Op::OpFOrdGreaterThanEqual) DEFINE_BINARY(OpFOrdGreaterThanEqual)
DEFINE_BINARY(OpFUnordGreaterThanEqual, spv::Op::OpFUnordGreaterThanEqual) DEFINE_BINARY(OpFUnordGreaterThanEqual)
} // namespace Sirit } // namespace Sirit

View file

@ -5,91 +5,64 @@
*/ */
#include <cassert> #include <cassert>
#include "op.h"
#include "sirit/sirit.h" #include "sirit/sirit.h"
#include "stream.h"
namespace Sirit { namespace Sirit {
Id Module::OpVariable(Id result_type, spv::StorageClass storage_class, Id initializer) {
auto op{std::make_unique<Op>(spv::Op::OpVariable, bound++, result_type)};
op->Add(static_cast<u32>(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) { Id Module::OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample) {
auto op{std::make_unique<Op>(spv::Op::OpImageTexelPointer, bound++, result_type)}; code->Reserve(6);
op->Add(image); return *code << OpId{spv::Op::OpImageTexelPointer, result_type} << image << coordinate << sample
op->Add(coordinate); << EndOp{};
op->Add(sample);
return AddCode(std::move(op));
} }
Id Module::OpLoad(Id result_type, Id pointer, std::optional<spv::MemoryAccessMask> memory_access) { Id Module::OpLoad(Id result_type, Id pointer, std::optional<spv::MemoryAccessMask> memory_access) {
auto op{std::make_unique<Op>(spv::Op::OpLoad, bound++, result_type)}; code->Reserve(5);
op->Add(pointer); return *code << OpId{spv::Op::OpLoad, result_type} << pointer << memory_access << EndOp{};
if (memory_access) {
op->Add(static_cast<u32>(*memory_access));
}
return AddCode(std::move(op));
} }
Id Module::OpStore(Id pointer, Id object, std::optional<spv::MemoryAccessMask> memory_access) { Id Module::OpStore(Id pointer, Id object, std::optional<spv::MemoryAccessMask> memory_access) {
auto op{std::make_unique<Op>(spv::Op::OpStore)}; code->Reserve(4);
op->Add(pointer); return *code << spv::Op::OpStore << pointer << object << memory_access << EndOp{};
op->Add(object);
if (memory_access) {
op->Add(static_cast<u32>(*memory_access));
}
return AddCode(std::move(op));
} }
Id Module::OpAccessChain(Id result_type, Id base, std::span<const Id> indexes) { Id Module::OpAccessChain(Id result_type, Id base, std::span<const Id> indexes) {
assert(indexes.size() > 0); assert(!indexes.empty());
auto op{std::make_unique<Op>(spv::Op::OpAccessChain, bound++, result_type)}; code->Reserve(4 + indexes.size());
op->Add(base); return *code << OpId{spv::Op::OpAccessChain, result_type} << base << indexes << EndOp{};
op->Add(indexes);
return AddCode(std::move(op));
} }
Id Module::OpVectorExtractDynamic(Id result_type, Id vector, Id index) { Id Module::OpVectorExtractDynamic(Id result_type, Id vector, Id index) {
auto op{std::make_unique<Op>(spv::Op::OpVectorExtractDynamic, bound++, result_type)}; code->Reserve(5);
op->Add(vector); return *code << OpId{spv::Op::OpVectorExtractDynamic, result_type} << vector << index
op->Add(index); << EndOp{};
return AddCode(std::move(op));
} }
Id Module::OpVectorInsertDynamic(Id result_type, Id vector, Id component, Id index) { Id Module::OpVectorInsertDynamic(Id result_type, Id vector, Id component, Id index) {
auto op{std::make_unique<Op>(spv::Op::OpVectorInsertDynamic, bound++, result_type)}; code->Reserve(6);
op->Add(vector); return *code << OpId{spv::Op::OpVectorInsertDynamic, result_type} << vector << component
op->Add(component); << index << EndOp{};
op->Add(index);
return AddCode(std::move(op));
} }
Id Module::OpCompositeInsert(Id result_type, Id object, Id composite, Id Module::OpCompositeInsert(Id result_type, Id object, Id composite,
std::span<const Literal> indexes) { std::span<const Literal> indexes) {
auto op{std::make_unique<Op>(spv::Op::OpCompositeInsert, bound++, result_type)}; code->Reserve(5 + indexes.size());
op->Add(object); return *code << OpId{spv::Op::OpCompositeInsert, result_type} << object << composite << indexes
op->Add(composite); << EndOp{};
op->Add(indexes);
return AddCode(std::move(op));
} }
Id Module::OpCompositeExtract(Id result_type, Id composite, std::span<const Literal> indexes) { Id Module::OpCompositeExtract(Id result_type, Id composite, std::span<const Literal> indexes) {
auto op{std::make_unique<Op>(spv::Op::OpCompositeExtract, bound++, result_type)}; code->Reserve(4 + indexes.size());
op->Add(composite); return *code << OpId{spv::Op::OpCompositeExtract, result_type} << composite << indexes
op->Add(indexes); << EndOp{};
return AddCode(std::move(op));
} }
Id Module::OpCompositeConstruct(Id result_type, std::span<const Id> ids) { Id Module::OpCompositeConstruct(Id result_type, std::span<const Id> ids) {
assert(ids.size() >= 1); assert(ids.size() >= 1);
auto op{std::make_unique<Op>(spv::Op::OpCompositeConstruct, bound++, result_type)}; code->Reserve(3 + ids.size());
op->Add(ids); return *code << OpId{spv::Op::OpCompositeConstruct, result_type} << ids << EndOp{};
return AddCode(std::move(op));
} }
} // namespace Sirit } // namespace Sirit

View file

@ -4,21 +4,25 @@
* 3-Clause BSD License * 3-Clause BSD License
*/ */
#include "op.h"
#include "sirit/sirit.h" #include "sirit/sirit.h"
#include "stream.h"
namespace Sirit { namespace Sirit {
Id Module::OpUndef(Id result_type) { Id Module::OpUndef(Id result_type) {
return AddCode(std::make_unique<Op>(spv::Op::OpUndef, bound++, result_type)); code->Reserve(3);
return *code << OpId{spv::Op::OpUndef, result_type} << EndOp{};
} }
Id Module::OpEmitVertex() { Id Module::OpEmitVertex() {
return AddCode(std::make_unique<Op>(spv::Op::OpEmitVertex)); code->Reserve(1);
return *code << OpId{spv::Op::OpEmitVertex} << EndOp{};
} }
Id Module::OpEndPrimitive() { Id Module::OpEndPrimitive() {
return AddCode(std::make_unique<Op>(spv::Op::OpEndPrimitive)); code->Reserve(1);
return *code << OpId{spv::Op::OpEndPrimitive} << EndOp{};
} }
} // namespace Sirit } // namespace Sirit

View file

@ -5,137 +5,118 @@
*/ */
#include <cassert> #include <cassert>
#include <memory>
#include <optional> #include <optional>
#include "op.h"
#include "sirit/sirit.h" #include "sirit/sirit.h"
#include "stream.h"
namespace Sirit { namespace Sirit {
Id Module::TypeVoid() { Id Module::TypeVoid() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeVoid, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeVoid} << EndOp{};
} }
Id Module::TypeBool() { Id Module::TypeBool() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeBool, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeBool} << EndOp{};
} }
Id Module::TypeInt(int width, bool is_signed) { Id Module::TypeInt(int width, bool is_signed) {
auto op{std::make_unique<Op>(spv::Op::OpTypeInt, bound)}; declarations->Reserve(4);
op->Add(width); return *declarations << OpId{spv::Op::OpTypeInt} << width << is_signed << EndOp{};
op->Add(is_signed ? 1 : 0);
return AddDeclaration(std::move(op));
} }
Id Module::TypeFloat(int width) { Id Module::TypeFloat(int width) {
auto op{std::make_unique<Op>(spv::Op::OpTypeFloat, bound)}; declarations->Reserve(3);
op->Add(width); return *declarations << OpId{spv::Op::OpTypeFloat} << width << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypeVector(Id component_type, int component_count) { Id Module::TypeVector(Id component_type, int component_count) {
assert(component_count >= 2); assert(component_count >= 2);
auto op{std::make_unique<Op>(spv::Op::OpTypeVector, bound)}; declarations->Reserve(4);
op->Add(component_type); return *declarations << OpId{spv::Op::OpTypeVector} << component_type << component_count
op->Add(component_count); << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypeMatrix(Id column_type, int column_count) { Id Module::TypeMatrix(Id column_type, int column_count) {
assert(column_count >= 2); assert(column_count >= 2);
auto op{std::make_unique<Op>(spv::Op::OpTypeMatrix, bound)}; declarations->Reserve(4);
op->Add(column_type); return *declarations << OpId{spv::Op::OpTypeMatrix} << column_type << column_count << EndOp{};
op->Add(column_count);
return AddDeclaration(std::move(op));
} }
Id Module::TypeImage(Id sampled_type, spv::Dim dim, int depth, bool arrayed, bool ms, int sampled, Id Module::TypeImage(Id sampled_type, spv::Dim dim, int depth, bool arrayed, bool ms, int sampled,
spv::ImageFormat image_format, spv::ImageFormat image_format,
std::optional<spv::AccessQualifier> access_qualifier) { std::optional<spv::AccessQualifier> access_qualifier) {
auto op{std::make_unique<Op>(spv::Op::OpTypeImage, bound)}; declarations->Reserve(10);
op->Add(sampled_type); return *declarations << OpId{spv::Op::OpTypeImage} << sampled_type << dim << depth << arrayed
op->Add(static_cast<u32>(dim)); << ms << sampled << image_format << access_qualifier << EndOp{};
op->Add(depth);
op->Add(arrayed ? 1 : 0);
op->Add(ms ? 1 : 0);
op->Add(sampled);
op->Add(static_cast<u32>(image_format));
if (access_qualifier.has_value()) {
op->Add(static_cast<u32>(access_qualifier.value()));
}
return AddDeclaration(std::move(op));
} }
Id Module::TypeSampler() { Id Module::TypeSampler() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeSampler, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeSampler} << EndOp{};
} }
Id Module::TypeSampledImage(Id image_type) { Id Module::TypeSampledImage(Id image_type) {
auto op{std::make_unique<Op>(spv::Op::OpTypeSampledImage, bound)}; declarations->Reserve(3);
op->Add(image_type); return *declarations << OpId{spv::Op::OpTypeSampledImage} << image_type << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypeArray(Id element_type, Id length) { Id Module::TypeArray(Id element_type, Id length) {
auto op{std::make_unique<Op>(spv::Op::OpTypeArray, bound)}; declarations->Reserve(4);
op->Add(element_type); return *declarations << OpId{spv::Op::OpTypeArray} << element_type << length << EndOp{};
op->Add(length);
return AddDeclaration(std::move(op));
} }
Id Module::TypeRuntimeArray(Id element_type) { Id Module::TypeRuntimeArray(Id element_type) {
auto op{std::make_unique<Op>(spv::Op::OpTypeRuntimeArray, bound)}; declarations->Reserve(3);
op->Add(element_type); return *declarations << OpId{spv::Op::OpTypeRuntimeArray} << element_type << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypeStruct(std::span<const Id> members) { Id Module::TypeStruct(std::span<const Id> members) {
auto op{std::make_unique<Op>(spv::Op::OpTypeStruct, bound)}; declarations->Reserve(2 + members.size());
op->Add(members); return *declarations << OpId{spv::Op::OpTypeStruct} << members << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypeOpaque(std::string name) { Id Module::TypeOpaque(std::string_view name) {
auto op{std::make_unique<Op>(spv::Op::OpTypeOpaque, bound)}; declarations->Reserve(3 + WordsInString(name));
op->Add(std::move(name)); return *declarations << OpId{spv::Op::OpTypeOpaque} << name << EndOp{};
return AddDeclaration(std::move(op));
} }
Id Module::TypePointer(spv::StorageClass storage_class, Id type) { Id Module::TypePointer(spv::StorageClass storage_class, Id type) {
auto op{std::make_unique<Op>(spv::Op::OpTypePointer, bound)}; declarations->Reserve(4);
op->Add(static_cast<u32>(storage_class)); return *declarations << OpId{spv::Op::OpTypePointer} << storage_class << type << EndOp{};
op->Add(type);
return AddDeclaration(std::move(op));
} }
Id Module::TypeFunction(Id return_type, std::span<const Id> arguments) { Id Module::TypeFunction(Id return_type, std::span<const Id> arguments) {
auto op{std::make_unique<Op>(spv::Op::OpTypeFunction, bound)}; declarations->Reserve(3 + arguments.size());
op->Add(return_type); return *declarations << OpId{spv::Op::OpTypeFunction} << return_type << arguments << EndOp{};
op->Add(arguments);
return AddDeclaration(std::move(op));
} }
Id Module::TypeEvent() { Id Module::TypeEvent() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeEvent, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeEvent} << EndOp{};
} }
Id Module::TypeDeviceEvent() { Id Module::TypeDeviceEvent() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeDeviceEvent, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeDeviceEvent} << EndOp{};
} }
Id Module::TypeReserveId() { Id Module::TypeReserveId() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeReserveId, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeReserveId} << EndOp{};
} }
Id Module::TypeQueue() { Id Module::TypeQueue() {
return AddDeclaration(std::make_unique<Op>(spv::Op::OpTypeQueue, bound)); declarations->Reserve(2);
return *declarations << OpId{spv::Op::OpTypeQueue} << EndOp{};
} }
Id Module::TypePipe(spv::AccessQualifier access_qualifier) { Id Module::TypePipe(spv::AccessQualifier access_qualifier) {
auto op{std::make_unique<Op>(spv::Op::OpTypePipe, bound)}; declarations->Reserve(2);
op->Add(static_cast<u32>(access_qualifier)); return *declarations << OpId{spv::Op::OpTypePipe} << access_qualifier << EndOp{};
return AddDeclaration(std::move(op));
} }
} // namespace Sirit } // namespace Sirit

View file

@ -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 <cassert>
#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<u32>(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<const LiteralNumber&>(other)};
return o.raw == raw && o.is_32 == is_32;
}
} // namespace Sirit

View file

@ -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 <cstddef>
#include <cstring>
#include <memory>
#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 <typename T>
static std::unique_ptr<LiteralNumber> Create(T value) {
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
u64 raw{};
std::memcpy(&raw, &value, sizeof(T));
return std::make_unique<LiteralNumber>(raw, sizeof(T) == 4);
}
private:
u64 raw{};
bool is_32{};
};
} // namespace Sirit

View file

@ -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 <string>
#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<const LiteralString&>(other).string == string;
}
} // namespace Sirit

View file

@ -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 <string>
#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

View file

@ -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 <algorithm>
#include <cassert>
#include <limits>
#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<u32> 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<const Op&>(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<u16>(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> operand) {
Add(static_cast<const Operand*>(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<const Literal> 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<LiteralString>(std::move(string)));
}
void Op::Add(std::span<const Id> 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<u16>::max());
return static_cast<u16>(count);
}
} // namespace Sirit

View file

@ -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 <cstddef>
#include <optional>
#include <vector>
#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<u32> 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> operand);
void Add(const Literal& literal);
void Add(std::span<const Literal> literals);
void Add(const Operand* operand);
void Add(u32 integer);
void Add(s32 integer);
void Add(std::string string);
void Add(std::span<const Id> ids);
private:
u16 CalculateTotalWords() const noexcept;
spv::Op opcode;
Id result_type;
std::optional<u32> id;
std::vector<const Operand*> operands;
std::vector<std::unique_ptr<Operand>> operand_store;
};
} // namespace Sirit

View file

@ -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 <cassert>
#include "operand.h"
namespace Sirit {
Operand::Operand(OperandType operand_type_) : operand_type{operand_type_} {}
Operand::~Operand() = default;
} // namespace Sirit

View file

@ -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 <cstddef>
#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

View file

@ -4,66 +4,66 @@
* 3-Clause BSD License * 3-Clause BSD License
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include "common_types.h"
#include "op.h"
#include "sirit/sirit.h" #include "sirit/sirit.h"
#include "common_types.h"
#include "stream.h" #include "stream.h"
namespace Sirit { namespace Sirit {
template <typename T> constexpr u32 MakeWord0(spv::Op op, size_t word_count) {
static void WriteSet(Stream& stream, const T& set) { return static_cast<u32>(op) | static_cast<u32>(word_count) << 16;
for (const auto& item : set) {
item->Write(stream);
}
} }
Module::Module(u32 version_) : version{version_} {} Module::Module(u32 version_)
: version{version_}, ext_inst_imports{std::make_unique<Stream>(&bound)},
entry_points{std::make_unique<Stream>(&bound)},
execution_modes{std::make_unique<Stream>(&bound)}, debug{std::make_unique<Stream>(&bound)},
annotations{std::make_unique<Stream>(&bound)}, declarations{std::make_unique<Declarations>(
&bound)},
global_variables{std::make_unique<Stream>(&bound)}, code{std::make_unique<Stream>(&bound)} {}
Module::~Module() = default; Module::~Module() = default;
std::vector<u32> Module::Assemble() const { std::vector<u32> Module::Assemble() const {
std::vector<u32> bytes; std::vector<u32> words = {spv::MagicNumber, version, GENERATOR_MAGIC_NUMBER, bound + 1, 0};
Stream stream{bytes}; const auto insert = [&words](std::span<const u32> input) {
words.insert(words.end(), input.begin(), input.end());
};
stream.Write(spv::MagicNumber); words.reserve(words.size() + capabilities.size() * 2);
stream.Write(version); for (const spv::Capability capability : capabilities) {
stream.Write(GENERATOR_MAGIC_NUMBER); insert(std::array{
stream.Write(bound); MakeWord0(spv::Op::OpCapability, 2),
stream.Write(static_cast<u32>(0)); static_cast<u32>(capability),
});
for (const auto capability : capabilities) {
Op op(spv::Op::OpCapability);
op.Add(static_cast<u32>(capability));
op.Write(stream);
} }
for (const auto& extension_name : extensions) { for (const std::string_view extension_name : extensions) {
Op op(spv::Op::OpExtension); size_t insert_index = words.size();
op.Add(extension_name); words.resize(words.size() + WordsInString(extension_name));
op.Write(stream); InsertStringView(words, insert_index, extension_name);
} }
if (glsl_std_450) { insert(ext_inst_imports->Words());
glsl_std_450->Write(stream);
}
Op memory_model_ref{spv::Op::OpMemoryModel}; insert(std::array{
memory_model_ref.Add(static_cast<u32>(addressing_model)); MakeWord0(spv::Op::OpMemoryModel, 3),
memory_model_ref.Add(static_cast<u32>(memory_model)); static_cast<u32>(addressing_model),
memory_model_ref.Write(stream); static_cast<u32>(memory_model),
});
WriteSet(stream, entry_points); insert(entry_points->Words());
WriteSet(stream, execution_modes); insert(execution_modes->Words());
WriteSet(stream, debug); insert(debug->Words());
WriteSet(stream, annotations); insert(annotations->Words());
WriteSet(stream, declarations); insert(declarations->Words());
WriteSet(stream, global_variables); insert(global_variables->Words());
WriteSet(stream, code); insert(code->Words());
return bytes; return words;
} }
void Module::AddExtension(std::string extension_name) { void Module::AddExtension(std::string extension_name) {
@ -76,75 +76,51 @@ void Module::AddCapability(spv::Capability capability) {
void Module::SetMemoryModel(spv::AddressingModel addressing_model_, void Module::SetMemoryModel(spv::AddressingModel addressing_model_,
spv::MemoryModel memory_model_) { spv::MemoryModel memory_model_) {
this->addressing_model = addressing_model_; addressing_model = addressing_model_;
this->memory_model = memory_model_; memory_model = memory_model_;
} }
void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string name, void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point,
std::span<const Id> interfaces) { std::string_view name, std::span<const Id> interfaces) {
auto op{std::make_unique<Op>(spv::Op::OpEntryPoint)}; entry_points->Reserve(4 + WordsInString(name) + interfaces.size());
op->Add(static_cast<u32>(execution_model)); *entry_points << spv::Op::OpEntryPoint << execution_model << entry_point << name << interfaces
op->Add(entry_point); << EndOp{};
op->Add(std::move(name));
op->Add(interfaces);
entry_points.push_back(std::move(op));
} }
void Module::AddExecutionMode(Id entry_point, spv::ExecutionMode mode, void Module::AddExecutionMode(Id entry_point, spv::ExecutionMode mode,
std::span<const Literal> literals) { std::span<const Literal> literals) {
auto op{std::make_unique<Op>(spv::Op::OpExecutionMode)}; execution_modes->Reserve(3 + literals.size());
op->Add(entry_point); *execution_modes << spv::Op::OpExecutionMode << entry_point << mode << literals << EndOp{};
op->Add(static_cast<u32>(mode));
op->Add(literals);
execution_modes.push_back(std::move(op));
} }
Id Module::AddLabel(Id label) { Id Module::AddLabel(Id label) {
assert(label != nullptr); assert(label.value != 0);
return code.emplace_back(label); code->Reserve(2);
*code << MakeWord0(spv::Op::OpLabel, 2) << label.value;
return label;
} }
Id Module::AddLocalVariable(Id variable) { Id Module::AddLocalVariable(Id result_type, spv::StorageClass storage_class,
assert(variable != nullptr); std::optional<Id> initializer) {
return code.emplace_back(variable); code->Reserve(5);
return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer
<< EndOp{};
} }
Id Module::AddGlobalVariable(Id variable) { Id Module::AddGlobalVariable(Id result_type, spv::StorageClass storage_class,
assert(variable); std::optional<Id> initializer) {
return global_variables.emplace_back(variable); code->Reserve(5);
} return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer
<< EndOp{};
Id Module::AddCode(std::unique_ptr<Op> 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<u32> id) {
return AddCode(std::make_unique<Op>(opcode, id));
}
Id Module::AddDeclaration(std::unique_ptr<Op> 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> op) {
annotations.push_back(std::move(op));
} }
Id Module::GetGLSLstd450() { Id Module::GetGLSLstd450() {
if (!glsl_std_450) { if (!glsl_std_450) {
glsl_std_450 = std::make_unique<Op>(spv::Op::OpExtInstImport, bound++); ext_inst_imports->Reserve(3 + 4);
glsl_std_450->Add("GLSL.std.450"); 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 } // namespace Sirit

View file

@ -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<u32>& 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<u8>(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<u32>(value), static_cast<u32>(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<u32>(first) | static_cast<u32>(second) << 16;
Write(word);
}
void Stream::Write(u8 first, u8 second, u8 third, u8 fourth) {
const u32 word = static_cast<u32>(first) | static_cast<u32>(second) << 8 |
static_cast<u32>(third) << 16 | static_cast<u32>(fourth) << 24;
Write(word);
}
} // namespace Sirit

View file

@ -6,29 +6,219 @@
#pragma once #pragma once
#include <bit>
#include <concepts>
#include <cstddef>
#include <functional>
#include <string_view> #include <string_view>
#include <unordered_map>
#include <variant>
#include <vector> #include <vector>
#include <spirv/unified1/spirv.hpp>
#include "common_types.h" #include "common_types.h"
namespace Sirit { 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<u32>& 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<u8>(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 { class Stream {
friend Declarations;
public: public:
explicit Stream(std::vector<u32>& words); explicit Stream(u32* bound_) : bound{bound_} {}
~Stream();
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<const u32> 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<u32>(op);
return *this;
}
void Write(u16 first, u16 second); Stream& operator<<(OpId op) {
op_index = insert_index;
words[insert_index++] = static_cast<u32>(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<u32>(num_words) << 16;
return Id{*bound};
}
Stream& operator<<(u32 value) {
words[insert_index++] = value;
return *this;
}
Stream& operator<<(s32 value) {
return *this << static_cast<u32>(value);
}
Stream& operator<<(u64 value) {
return *this << static_cast<u32>(value) << static_cast<u32>(value >> 32);
}
Stream& operator<<(s64 value) {
return *this << static_cast<u64>(value);
}
Stream& operator<<(float value) {
return *this << std::bit_cast<u32>(value);
}
Stream& operator<<(double value) {
return *this << std::bit_cast<u64>(value);
}
Stream& operator<<(bool value) {
return *this << static_cast<u32>(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 <typename T>
requires std::is_enum_v<T> Stream& operator<<(T value) {
static_assert(sizeof(T) == sizeof(u32));
return *this << static_cast<u32>(value);
}
template <typename T>
Stream& operator<<(std::optional<T> value) {
if (value) {
*this << *value;
}
return *this;
}
template <typename T>
Stream& operator<<(std::span<const T> values) {
for (const auto& value : values) {
*this << value;
}
return *this;
}
private: private:
std::vector<u32>& words; u32* bound = nullptr;
std::vector<u32> 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<const u32> Words() const noexcept {
return stream.Words();
}
template <typename T>
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<u32> 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<u32>& vector) const noexcept {
size_t hash = std::hash<size_t>{}(vector.size());
for (const u32 value : vector) {
hash ^= std::hash<u32>{}(value);
}
return hash;
}
};
Stream stream;
std::unordered_map<std::vector<u32>, u32, HashVector> existing_declarations;
size_t id_index = 0;
}; };
} // namespace Sirit } // namespace Sirit

View file

@ -7,6 +7,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <sirit/sirit.h> #include <sirit/sirit.h>
class MyModule : public Sirit::Module { class MyModule : public Sirit::Module {
@ -31,9 +32,9 @@ public:
const auto gl_per_vertex_ptr = const auto gl_per_vertex_ptr =
Name(TypePointer(spv::StorageClass::Output, gl_per_vertex), "out_gl_PerVertex"); 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 = 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(in_pos, spv::Decoration::Location, 0);
Decorate(gl_per_vertex, spv::Decoration::Block); Decorate(gl_per_vertex, spv::Decoration::Block);
@ -41,9 +42,6 @@ public:
MemberDecorate(gl_per_vertex, 0, spv::Decoration::BuiltIn, MemberDecorate(gl_per_vertex, 0, spv::Decoration::BuiltIn,
static_cast<std::uint32_t>(spv::BuiltIn::Position)); static_cast<std::uint32_t>(spv::BuiltIn::Position));
AddGlobalVariable(in_pos);
AddGlobalVariable(per_vertex);
const auto main_func = Name( const auto main_func = Name(
OpFunction(t_void, spv::FunctionControlMask::MaskNone, TypeFunction(t_void)), "main"); OpFunction(t_void, spv::FunctionControlMask::MaskNone, TypeFunction(t_void)), "main");
AddLabel(); AddLabel();
@ -57,8 +55,8 @@ public:
auto tmp_position = OpUndef(float4); auto tmp_position = OpUndef(float4);
tmp_position = OpCompositeInsert(float4, pos_x, tmp_position, 0); tmp_position = OpCompositeInsert(float4, pos_x, tmp_position, 0);
tmp_position = OpCompositeInsert(float4, pos_y, tmp_position, 1); 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, 0.0f), tmp_position, 2);
tmp_position = OpCompositeInsert(float4, Constant(t_float, 1.f), tmp_position, 3); 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)); const auto gl_position = OpAccessChain(out_float4, per_vertex, Constant(t_uint, 0u));
OpStore(gl_position, tmp_position); 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, 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, 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, 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) { int main(int argc, char** argv) {
MyModule module; MyModule module;