aboutsummaryrefslogtreecommitdiff
path: root/externals/sirit/src
diff options
context:
space:
mode:
authorDawid Potocki <dawid@dawidpotocki.com>2024-03-05 14:09:27 +1300
committerDawid Potocki <dawid@dawidpotocki.com>2024-03-05 20:34:15 +1300
commit063e15900bda8453fb0fc6751e78d064501ccbae (patch)
treea4cd5f01dbca33a262333aff10e1e035217a30c8 /externals/sirit/src
parent537296095ab24eddcb196b5ef98004f91de9c8c2 (diff)
Replace broken submodules with vendored source codeHEADpatched
Diffstat (limited to 'externals/sirit/src')
-rw-r--r--externals/sirit/src/.gitignore1
-rw-r--r--externals/sirit/src/CMakeLists.txt32
-rw-r--r--externals/sirit/src/common_types.h31
-rw-r--r--externals/sirit/src/instructions/annotation.cpp27
-rw-r--r--externals/sirit/src/instructions/arithmetic.cpp44
-rw-r--r--externals/sirit/src/instructions/atomic.cpp104
-rw-r--r--externals/sirit/src/instructions/barrier.cpp23
-rw-r--r--externals/sirit/src/instructions/bit.cpp76
-rw-r--r--externals/sirit/src/instructions/constant.cpp48
-rw-r--r--externals/sirit/src/instructions/conversion.cpp29
-rw-r--r--externals/sirit/src/instructions/debug.cpp36
-rw-r--r--externals/sirit/src/instructions/derivatives.cpp29
-rw-r--r--externals/sirit/src/instructions/extension.cpp76
-rw-r--r--externals/sirit/src/instructions/flow.cpp109
-rw-r--r--externals/sirit/src/instructions/function.cpp34
-rw-r--r--externals/sirit/src/instructions/group.cpp88
-rw-r--r--externals/sirit/src/instructions/image.cpp169
-rw-r--r--externals/sirit/src/instructions/logical.cpp65
-rw-r--r--externals/sirit/src/instructions/memory.cpp68
-rw-r--r--externals/sirit/src/instructions/misc.cpp38
-rw-r--r--externals/sirit/src/instructions/type.cpp130
-rw-r--r--externals/sirit/src/sirit.cpp142
-rw-r--r--externals/sirit/src/stream.cpp0
-rw-r--r--externals/sirit/src/stream.h266
24 files changed, 1665 insertions, 0 deletions
diff --git a/externals/sirit/src/.gitignore b/externals/sirit/src/.gitignore
new file mode 100644
index 0000000000..06d55cbb24
--- /dev/null
+++ b/externals/sirit/src/.gitignore
@@ -0,0 +1 @@
+sirit.h
diff --git a/externals/sirit/src/CMakeLists.txt b/externals/sirit/src/CMakeLists.txt
new file mode 100644
index 0000000000..18f3e1b112
--- /dev/null
+++ b/externals/sirit/src/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_library(sirit
+ ../include/sirit/sirit.h
+ sirit.cpp
+ stream.h
+ common_types.h
+ instructions/type.cpp
+ instructions/constant.cpp
+ instructions/function.cpp
+ instructions/flow.cpp
+ instructions/debug.cpp
+ instructions/derivatives.cpp
+ instructions/memory.cpp
+ instructions/annotation.cpp
+ instructions/misc.cpp
+ instructions/logical.cpp
+ instructions/conversion.cpp
+ instructions/bit.cpp
+ instructions/arithmetic.cpp
+ instructions/extension.cpp
+ instructions/image.cpp
+ instructions/group.cpp
+ instructions/barrier.cpp
+ instructions/atomic.cpp
+)
+
+target_compile_options(sirit PRIVATE ${SIRIT_CXX_FLAGS})
+
+target_include_directories(sirit
+ PUBLIC ../include
+ PRIVATE .)
+
+target_link_libraries(sirit PUBLIC SPIRV-Headers::SPIRV-Headers)
diff --git a/externals/sirit/src/common_types.h b/externals/sirit/src/common_types.h
new file mode 100644
index 0000000000..42df6f6c3b
--- /dev/null
+++ b/externals/sirit/src/common_types.h
@@ -0,0 +1,31 @@
+/* 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 <cstdint>
+
+namespace Sirit {
+
+using u8 = std::uint8_t;
+using u16 = std::uint16_t;
+using u32 = std::uint32_t;
+using u64 = std::uint64_t;
+using uptr = std::uintptr_t;
+
+using s8 = std::int8_t;
+using s16 = std::int16_t;
+using s32 = std::int32_t;
+using s64 = std::int64_t;
+using sptr = std::intptr_t;
+
+using f32 = float;
+using f64 = double;
+static_assert(sizeof(f32) == sizeof(u32), "f32 must be 32 bits wide");
+static_assert(sizeof(f64) == sizeof(u64), "f64 must be 64 bits wide");
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/annotation.cpp b/externals/sirit/src/instructions/annotation.cpp
new file mode 100644
index 0000000000..e3524bb83a
--- /dev/null
+++ b/externals/sirit/src/instructions/annotation.cpp
@@ -0,0 +1,27 @@
+/* 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 <span>
+
+#include "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::Decorate(Id target, spv::Decoration decoration, std::span<const Literal> literals) {
+ annotations->Reserve(3 + literals.size());
+ return *annotations << spv::Op::OpDecorate << target << decoration << literals << EndOp{};
+}
+
+Id Module::MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration,
+ std::span<const Literal> literals) {
+ annotations->Reserve(4 + literals.size());
+ return *annotations << spv::Op::OpMemberDecorate << structure_type << member << decoration
+ << literals << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/arithmetic.cpp b/externals/sirit/src/instructions/arithmetic.cpp
new file mode 100644
index 0000000000..4fa8057e37
--- /dev/null
+++ b/externals/sirit/src/instructions/arithmetic.cpp
@@ -0,0 +1,44 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+#define DEFINE_UNARY(funcname, opcode) \
+ Id Module::funcname(Id result_type, Id operand) { \
+ 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) { \
+ code->Reserve(5); \
+ return *code << OpId{opcode, result_type} << operand_1 << operand_2 << EndOp{}; \
+ }
+
+DEFINE_UNARY(OpSNegate, spv::Op::OpSNegate)
+DEFINE_UNARY(OpFNegate, spv::Op::OpFNegate)
+
+DEFINE_BINARY(OpIAdd, spv::Op::OpIAdd)
+DEFINE_BINARY(OpFAdd, spv::Op::OpFAdd)
+DEFINE_BINARY(OpISub, spv::Op::OpISub)
+DEFINE_BINARY(OpFSub, spv::Op::OpFSub)
+DEFINE_BINARY(OpIMul, spv::Op::OpIMul)
+DEFINE_BINARY(OpFMul, spv::Op::OpFMul)
+DEFINE_BINARY(OpUDiv, spv::Op::OpUDiv)
+DEFINE_BINARY(OpSDiv, spv::Op::OpSDiv)
+DEFINE_BINARY(OpFDiv, spv::Op::OpFDiv)
+DEFINE_BINARY(OpUMod, spv::Op::OpUMod)
+DEFINE_BINARY(OpSMod, spv::Op::OpSMod)
+DEFINE_BINARY(OpFMod, spv::Op::OpFMod)
+DEFINE_BINARY(OpSRem, spv::Op::OpSRem)
+DEFINE_BINARY(OpFRem, spv::Op::OpFRem)
+DEFINE_BINARY(OpIAddCarry, spv::Op::OpIAddCarry)
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/atomic.cpp b/externals/sirit/src/instructions/atomic.cpp
new file mode 100644
index 0000000000..cee8849f57
--- /dev/null
+++ b/externals/sirit/src/instructions/atomic.cpp
@@ -0,0 +1,104 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ code->Reserve(7);
+ return *code << OpId{spv::Op::OpAtomicXor, result_type} << pointer << memory << semantics
+ << value << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/barrier.cpp b/externals/sirit/src/instructions/barrier.cpp
new file mode 100644
index 0000000000..646b5cfb4d
--- /dev/null
+++ b/externals/sirit/src/instructions/barrier.cpp
@@ -0,0 +1,23 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpControlBarrier(Id execution, Id memory, Id semantics) {
+ code->Reserve(4);
+ return *code << spv::Op::OpControlBarrier << execution << memory << semantics << EndOp{};
+}
+
+Id Module::OpMemoryBarrier(Id scope, Id semantics) {
+ code->Reserve(3);
+ return *code << spv::Op::OpMemoryBarrier << scope << semantics << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/bit.cpp b/externals/sirit/src/instructions/bit.cpp
new file mode 100644
index 0000000000..c860613fcf
--- /dev/null
+++ b/externals/sirit/src/instructions/bit.cpp
@@ -0,0 +1,76 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpShiftRightLogical(Id result_type, Id base, Id shift) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpShiftRightLogical, result_type} << base << shift << EndOp{};
+}
+
+Id Module::OpShiftRightArithmetic(Id result_type, Id base, Id shift) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpShiftRightArithmetic, result_type} << base << shift << EndOp{};
+}
+
+Id Module::OpShiftLeftLogical(Id result_type, Id base, Id shift) {
+ 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) {
+ 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) {
+ 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) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpBitwiseAnd, result_type} << operand_1 << operand_2 << EndOp{};
+}
+
+Id Module::OpNot(Id result_type, Id operand) {
+ 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) {
+ 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) {
+ 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) {
+ code->Reserve(6);
+ return *code << OpId{spv::Op::OpBitFieldUExtract, result_type} << base << offset << count
+ << EndOp{};
+}
+
+Id Module::OpBitReverse(Id result_type, Id base) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpBitReverse, result_type} << base << EndOp{};
+}
+
+Id Module::OpBitCount(Id result_type, Id base) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpBitCount, result_type} << base << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/constant.cpp b/externals/sirit/src/instructions/constant.cpp
new file mode 100644
index 0000000000..612049c4f8
--- /dev/null
+++ b/externals/sirit/src/instructions/constant.cpp
@@ -0,0 +1,48 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::ConstantTrue(Id result_type) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpConstantTrue, result_type} << EndOp{};
+}
+
+Id Module::ConstantFalse(Id result_type) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpConstantFalse, result_type} << EndOp{};
+}
+
+Id Module::Constant(Id result_type, const Literal& literal) {
+ declarations->Reserve(3 + 2);
+ return *declarations << OpId{spv::Op::OpConstant, result_type} << literal << EndOp{};
+}
+
+Id Module::ConstantComposite(Id result_type, std::span<const Id> constituents) {
+ 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) {
+ declarations->Reserve(6);
+ return *declarations << OpId{spv::Op::OpConstantSampler, result_type} << addressing_mode
+ << normalized << filter_mode << EndOp{};
+}
+
+Id Module::ConstantNull(Id result_type) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpConstantNull, result_type} << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/conversion.cpp b/externals/sirit/src/instructions/conversion.cpp
new file mode 100644
index 0000000000..0b4e2c8a3f
--- /dev/null
+++ b/externals/sirit/src/instructions/conversion.cpp
@@ -0,0 +1,29 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+#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_UNARY(OpConvertFToU)
+DEFINE_UNARY(OpConvertFToS)
+DEFINE_UNARY(OpConvertSToF)
+DEFINE_UNARY(OpConvertUToF)
+DEFINE_UNARY(OpUConvert)
+DEFINE_UNARY(OpSConvert)
+DEFINE_UNARY(OpFConvert)
+DEFINE_UNARY(OpQuantizeToF16)
+DEFINE_UNARY(OpBitcast)
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/debug.cpp b/externals/sirit/src/instructions/debug.cpp
new file mode 100644
index 0000000000..1ca3462654
--- /dev/null
+++ b/externals/sirit/src/instructions/debug.cpp
@@ -0,0 +1,36 @@
+/* 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 "sirit/sirit.h"
+
+#include "common_types.h"
+#include "stream.h"
+
+namespace Sirit {
+
+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_view name) {
+ debug->Reserve(4 + WordsInString(name));
+ *debug << spv::Op::OpMemberName << type << member << name << EndOp{};
+ return type;
+}
+
+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) {
+ debug->Reserve(4);
+ return *debug << spv::Op::OpLine << file << line << column << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/derivatives.cpp b/externals/sirit/src/instructions/derivatives.cpp
new file mode 100644
index 0000000000..c944e2a52a
--- /dev/null
+++ b/externals/sirit/src/instructions/derivatives.cpp
@@ -0,0 +1,29 @@
+/* This file is part of the sirit project.
+ * Copyright (c) 2021 sirit
+ * This software may be used and distributed according to the terms of the
+ * 3-Clause BSD License
+ */
+
+#include "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+#define DEFINE_UNARY(funcname, opcode) \
+ Id Module::funcname(Id result_type, Id operand) { \
+ code->Reserve(4); \
+ return *code << OpId{opcode, result_type} << operand << EndOp{}; \
+ }
+
+DEFINE_UNARY(OpDPdx, spv::Op::OpDPdx)
+DEFINE_UNARY(OpDPdy, spv::Op::OpDPdy)
+DEFINE_UNARY(OpFwidth, spv::Op::OpFwidth)
+DEFINE_UNARY(OpDPdxFine, spv::Op::OpDPdxFine)
+DEFINE_UNARY(OpDPdyFine, spv::Op::OpDPdyFine)
+DEFINE_UNARY(OpFwidthFine, spv::Op::OpFwidthFine)
+DEFINE_UNARY(OpDPdxCoarse, spv::Op::OpDPdxCoarse)
+DEFINE_UNARY(OpDPdyCoarse, spv::Op::OpDPdyCoarse)
+DEFINE_UNARY(OpFwidthCoarse, spv::Op::OpFwidthCoarse)
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/extension.cpp b/externals/sirit/src/instructions/extension.cpp
new file mode 100644
index 0000000000..9f7aa43050
--- /dev/null
+++ b/externals/sirit/src/instructions/extension.cpp
@@ -0,0 +1,76 @@
+/* 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 <spirv/unified1/GLSL.std.450.h>
+
+#include "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpExtInst(Id result_type, Id set, u32 instruction, std::span<const Id> operands) {
+ code->Reserve(5 + operands.size());
+ return *code << OpId{spv::Op::OpExtInst, result_type} << set << instruction << operands
+ << EndOp{};
+}
+
+#define DEFINE_UNARY(funcname, opcode) \
+ Id Module::funcname(Id result_type, Id operand) { \
+ return OpExtInst(result_type, GetGLSLstd450(), opcode, operand); \
+ }
+
+#define DEFINE_BINARY(funcname, opcode) \
+ Id Module::funcname(Id result_type, Id operand_1, Id operand_2) { \
+ return OpExtInst(result_type, GetGLSLstd450(), opcode, operand_1, operand_2); \
+ }
+
+#define DEFINE_TRINARY(funcname, opcode) \
+ Id Module::funcname(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
+ return OpExtInst(result_type, GetGLSLstd450(), opcode, operand_1, operand_2, operand_3); \
+ }
+
+DEFINE_UNARY(OpFAbs, GLSLstd450FAbs)
+DEFINE_UNARY(OpSAbs, GLSLstd450SAbs)
+DEFINE_UNARY(OpRound, GLSLstd450Round)
+DEFINE_UNARY(OpRoundEven, GLSLstd450RoundEven)
+DEFINE_UNARY(OpTrunc, GLSLstd450Trunc)
+DEFINE_UNARY(OpFSign, GLSLstd450FSign)
+DEFINE_UNARY(OpSSign, GLSLstd450SSign)
+DEFINE_UNARY(OpFloor, GLSLstd450Floor)
+DEFINE_UNARY(OpCeil, GLSLstd450Ceil)
+DEFINE_UNARY(OpFract, GLSLstd450Fract)
+DEFINE_UNARY(OpSin, GLSLstd450Sin)
+DEFINE_UNARY(OpCos, GLSLstd450Cos)
+DEFINE_UNARY(OpAsin, GLSLstd450Asin)
+DEFINE_UNARY(OpAcos, GLSLstd450Acos)
+DEFINE_BINARY(OpPow, GLSLstd450Pow)
+DEFINE_UNARY(OpExp, GLSLstd450Exp)
+DEFINE_UNARY(OpLog, GLSLstd450Log)
+DEFINE_UNARY(OpExp2, GLSLstd450Exp2)
+DEFINE_UNARY(OpLog2, GLSLstd450Log2)
+DEFINE_UNARY(OpSqrt, GLSLstd450Sqrt)
+DEFINE_UNARY(OpInverseSqrt, GLSLstd450InverseSqrt)
+DEFINE_BINARY(OpFMin, GLSLstd450FMin)
+DEFINE_BINARY(OpUMin, GLSLstd450UMin)
+DEFINE_BINARY(OpSMin, GLSLstd450SMin)
+DEFINE_BINARY(OpFMax, GLSLstd450FMax)
+DEFINE_BINARY(OpUMax, GLSLstd450UMax)
+DEFINE_BINARY(OpSMax, GLSLstd450SMax)
+DEFINE_TRINARY(OpFClamp, GLSLstd450FClamp)
+DEFINE_TRINARY(OpUClamp, GLSLstd450UClamp)
+DEFINE_TRINARY(OpSClamp, GLSLstd450SClamp)
+DEFINE_TRINARY(OpFma, GLSLstd450Fma)
+DEFINE_UNARY(OpPackHalf2x16, GLSLstd450PackHalf2x16)
+DEFINE_UNARY(OpUnpackHalf2x16, GLSLstd450UnpackHalf2x16)
+DEFINE_UNARY(OpFindILsb, GLSLstd450FindILsb)
+DEFINE_UNARY(OpFindSMsb, GLSLstd450FindSMsb)
+DEFINE_UNARY(OpFindUMsb, GLSLstd450FindUMsb)
+DEFINE_UNARY(OpInterpolateAtCentroid, GLSLstd450InterpolateAtCentroid)
+DEFINE_BINARY(OpInterpolateAtSample, GLSLstd450InterpolateAtSample)
+DEFINE_BINARY(OpInterpolateAtOffset, GLSLstd450InterpolateAtOffset)
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/flow.cpp b/externals/sirit/src/instructions/flow.cpp
new file mode 100644
index 0000000000..5f6b693d54
--- /dev/null
+++ b/externals/sirit/src/instructions/flow.cpp
@@ -0,0 +1,109 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpPhi(Id result_type, std::span<const Id> operands) {
+ assert(operands.size() % 2 == 0);
+ code->Reserve(3 + operands.size());
+ return *code << OpId{spv::Op::OpPhi, result_type} << operands << EndOp{};
+}
+
+Id Module::DeferredOpPhi(Id result_type, std::span<const Id> blocks) {
+ deferred_phi_nodes.push_back(code->LocalAddress());
+ code->Reserve(3 + blocks.size() * 2);
+ *code << OpId{spv::Op::OpPhi, result_type};
+ for (const Id block : blocks) {
+ *code << u32{0} << block;
+ }
+ return *code << EndOp{};
+}
+
+Id Module::OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control,
+ std::span<const Id> literals) {
+ 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) {
+ code->Reserve(3);
+ return *code << spv::Op::OpSelectionMerge << merge_block << selection_control << EndOp{};
+}
+
+Id Module::OpLabel() {
+ return Id{++bound};
+}
+
+Id Module::OpBranch(Id target_label) {
+ 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) {
+ code->Reserve(6);
+ *code << spv::Op::OpBranchConditional << condition << true_label << false_label;
+ if (true_weight != 0 || false_weight != 0) {
+ *code << true_weight << false_weight;
+ }
+ return *code << EndOp{};
+}
+
+Id Module::OpSwitch(Id selector, Id default_label, std::span<const Literal> literals,
+ std::span<const Id> labels) {
+ assert(literals.size() == labels.size());
+ 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) {
+ *code << literals[i] << labels[i];
+ }
+ return *code << EndOp{};
+}
+
+void Module::OpReturn() {
+ code->Reserve(1);
+ *code << spv::Op::OpReturn << EndOp{};
+}
+
+void Module::OpUnreachable() {
+ code->Reserve(1);
+ *code << spv::Op::OpUnreachable << EndOp{};
+}
+
+Id Module::OpReturnValue(Id value) {
+ code->Reserve(2);
+ return *code << spv::Op::OpReturnValue << value << EndOp{};
+}
+
+void Module::OpKill() {
+ code->Reserve(1);
+ *code << spv::Op::OpKill << EndOp{};
+}
+
+void Module::OpDemoteToHelperInvocation() {
+ code->Reserve(1);
+ *code << spv::Op::OpDemoteToHelperInvocation << EndOp{};
+}
+
+void Module::OpDemoteToHelperInvocationEXT() {
+ OpDemoteToHelperInvocation();
+}
+
+void Module::OpTerminateInvocation() {
+ code->Reserve(1);
+ *code << spv::Op::OpTerminateInvocation << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/function.cpp b/externals/sirit/src/instructions/function.cpp
new file mode 100644
index 0000000000..f84cd7ff53
--- /dev/null
+++ b/externals/sirit/src/instructions/function.cpp
@@ -0,0 +1,34 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpFunction(Id result_type, spv::FunctionControlMask function_control, Id function_type) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpFunction, result_type} << function_control << function_type
+ << EndOp{};
+}
+
+void Module::OpFunctionEnd() {
+ code->Reserve(1);
+ *code << spv::Op::OpFunctionEnd << EndOp{};
+}
+
+Id Module::OpFunctionCall(Id result_type, Id function, std::span<const Id> arguments) {
+ code->Reserve(4 + arguments.size());
+ return *code << OpId{spv::Op::OpFunctionCall, result_type} << function << arguments << EndOp{};
+}
+
+Id Module::OpFunctionParameter(Id result_type) {
+ code->Reserve(3);
+ return *code << OpId{spv::Op::OpFunctionParameter, result_type} << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/group.cpp b/externals/sirit/src/instructions/group.cpp
new file mode 100644
index 0000000000..b8532847a1
--- /dev/null
+++ b/externals/sirit/src/instructions/group.cpp
@@ -0,0 +1,88 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpSubgroupBallotKHR(Id result_type, Id predicate) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpSubgroupBallotKHR, result_type} << predicate << EndOp{};
+}
+
+Id Module::OpSubgroupReadInvocationKHR(Id result_type, Id value, Id index) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpSubgroupReadInvocationKHR, result_type} << value << index
+ << EndOp{};
+}
+
+Id Module::OpSubgroupAllKHR(Id result_type, Id predicate) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpSubgroupAllKHR, result_type} << predicate << EndOp{};
+}
+
+Id Module::OpSubgroupAnyKHR(Id result_type, Id predicate) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpSubgroupAnyKHR, result_type} << predicate << EndOp{};
+}
+
+Id Module::OpSubgroupAllEqualKHR(Id result_type, Id predicate) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpSubgroupAllEqualKHR, result_type} << predicate << EndOp{};
+}
+
+Id Module::OpGroupNonUniformElect(Id result_type, Id scope) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpGroupNonUniformElect, result_type} << scope << EndOp{};
+}
+
+Id Module::OpGroupNonUniformBroadcastFirst(Id result_type, Id scope, Id value) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpGroupNonUniformBroadcastFirst, result_type} << scope << value
+ << EndOp{};
+}
+
+Id Module::OpGroupNonUniformBroadcast(Id result_type, Id scope, Id value, Id id) {
+ code->Reserve(6);
+ return *code << OpId{spv::Op::OpGroupNonUniformBroadcast, result_type} << scope << value
+ << id << EndOp{};
+}
+
+Id Module::OpGroupNonUniformShuffle(Id result_type, Id scope, Id value, Id id) {
+ code->Reserve(6);
+ return *code << OpId{spv::Op::OpGroupNonUniformShuffle, result_type} << scope << value << id
+ << EndOp{};
+}
+
+Id Module::OpGroupNonUniformShuffleXor(Id result_type, Id scope, Id value, Id mask) {
+ code->Reserve(6);
+ return *code << OpId{spv::Op::OpGroupNonUniformShuffleXor, result_type} << scope << value
+ << mask << EndOp{};
+}
+
+Id Module::OpGroupNonUniformAll(Id result_type, Id scope, Id predicate) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpGroupNonUniformAll, result_type} << scope << predicate << EndOp{};
+}
+
+Id Module::OpGroupNonUniformAny(Id result_type, Id scope, Id predicate) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpGroupNonUniformAny, result_type} << scope << predicate << EndOp{};
+}
+
+Id Module::OpGroupNonUniformAllEqual(Id result_type, Id scope, Id value) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpGroupNonUniformAllEqual, result_type} << scope << value << EndOp{};
+}
+
+Id Module::OpGroupNonUniformBallot(Id result_type, Id scope, Id predicate) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpGroupNonUniformBallot, result_type} << scope << predicate << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/image.cpp b/externals/sirit/src/instructions/image.cpp
new file mode 100644
index 0000000000..e68447f1e9
--- /dev/null
+++ b/externals/sirit/src/instructions/image.cpp
@@ -0,0 +1,169 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+#define DEFINE_IMAGE_OP(opcode) \
+ Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \
+ std::optional<spv::ImageOperandsMask> image_operands, \
+ std::span<const Id> operands) { \
+ code->Reserve(6 + operands.size()); \
+ return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate \
+ << image_operands << operands << EndOp{}; \
+ }
+
+#define DEFINE_IMAGE_EXP_OP(opcode) \
+ Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, \
+ spv::ImageOperandsMask image_operands, std::span<const Id> operands) { \
+ code->Reserve(6 + operands.size()); \
+ return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate \
+ << image_operands << operands << EndOp{}; \
+ }
+
+#define DEFINE_IMAGE_EXTRA_OP(opcode) \
+ Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \
+ std::optional<spv::ImageOperandsMask> image_operands, \
+ std::span<const Id> operands) { \
+ code->Reserve(7 + operands.size()); \
+ return *code << OpId{spv::Op::opcode, result_type} << sampled_image << coordinate << extra \
+ << image_operands << operands << EndOp{}; \
+ }
+
+#define DEFINE_IMAGE_EXTRA_EXP_OP(opcode) \
+ Id Module::opcode(Id result_type, Id sampled_image, Id coordinate, Id extra, \
+ spv::ImageOperandsMask image_operands, std::span<const Id> operands) { \
+ 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) { \
+ 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) { \
+ code->Reserve(5); \
+ return *code << OpId{spv::Op::opcode, result_type} << image << extra << EndOp{}; \
+ }
+
+DEFINE_IMAGE_OP(OpImageSampleImplicitLod)
+DEFINE_IMAGE_EXP_OP(OpImageSampleExplicitLod)
+DEFINE_IMAGE_EXTRA_OP(OpImageSampleDrefImplicitLod)
+DEFINE_IMAGE_EXTRA_EXP_OP(OpImageSampleDrefExplicitLod)
+DEFINE_IMAGE_OP(OpImageSampleProjImplicitLod)
+DEFINE_IMAGE_EXP_OP(OpImageSampleProjExplicitLod)
+DEFINE_IMAGE_EXTRA_OP(OpImageSampleProjDrefImplicitLod)
+DEFINE_IMAGE_EXTRA_EXP_OP(OpImageSampleProjDrefExplicitLod)
+DEFINE_IMAGE_OP(OpImageFetch)
+DEFINE_IMAGE_EXTRA_OP(OpImageGather)
+DEFINE_IMAGE_EXTRA_OP(OpImageDrefGather)
+DEFINE_IMAGE_OP(OpImageRead)
+DEFINE_IMAGE_QUERY_BIN_OP(OpImageQuerySizeLod)
+DEFINE_IMAGE_QUERY_OP(OpImageQuerySize)
+DEFINE_IMAGE_QUERY_BIN_OP(OpImageQueryLod)
+DEFINE_IMAGE_QUERY_OP(OpImageQueryLevels)
+DEFINE_IMAGE_QUERY_OP(OpImageQuerySamples)
+
+Id Module::OpSampledImage(Id result_type, Id image, Id sampler) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpSampledImage, result_type} << image << sampler << EndOp{};
+}
+
+Id Module::OpImageWrite(Id image, Id coordinate, Id texel,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ 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) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpImage, result_type} << sampled_image << EndOp{};
+}
+
+Id Module::OpImageSparseSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseSampleImplicitLod, result_type} << sampled_image
+ << coordinate << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate,
+ spv::ImageOperandsMask image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(6 + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseSampleExplicitLod, result_type} << sampled_image
+ << coordinate << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseSampleDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate,
+ Id dref,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(6 + (image_operands.has_value() ? 1 : 0) + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseSampleDrefImplicitLod, result_type} << sampled_image
+ << coordinate << dref << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate,
+ Id dref, spv::ImageOperandsMask image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(7 + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseSampleDrefExplicitLod, result_type} << sampled_image
+ << coordinate << dref << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseFetch(Id result_type, Id image, Id coordinate,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseFetch, result_type} << image << coordinate
+ << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseGather(Id result_type, Id sampled_image, Id coordinate, Id component,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(6 + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseGather, result_type} << sampled_image << coordinate
+ << component << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(6 + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseDrefGather, result_type} << sampled_image
+ << coordinate << dref << image_operands << operands << EndOp{};
+}
+
+Id Module::OpImageSparseTexelsResident(Id result_type, Id resident_code) {
+ code->Reserve(4);
+ return *code << OpId{spv::Op::OpImageSparseTexelsResident, result_type} << resident_code
+ << EndOp{};
+}
+
+Id Module::OpImageSparseRead(Id result_type, Id image, Id coordinate,
+ std::optional<spv::ImageOperandsMask> image_operands,
+ std::span<const Id> operands) {
+ code->Reserve(5 + (image_operands.has_value() ? 1 : 0) + operands.size());
+ return *code << OpId{spv::Op::OpImageSparseTexelsResident, result_type} << image << coordinate
+ << image_operands << operands << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/logical.cpp b/externals/sirit/src/instructions/logical.cpp
new file mode 100644
index 0000000000..4d7292bf02
--- /dev/null
+++ b/externals/sirit/src/instructions/logical.cpp
@@ -0,0 +1,65 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+#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(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(opcode) \
+ Id Module::opcode(Id result_type, Id operand_1, Id operand_2, Id operand_3) { \
+ code->Reserve(6); \
+ return *code << OpId{spv::Op::opcode, result_type} << operand_1 << operand_2 << operand_3 \
+ << EndOp{}; \
+ }
+
+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/externals/sirit/src/instructions/memory.cpp b/externals/sirit/src/instructions/memory.cpp
new file mode 100644
index 0000000000..a542e9fcca
--- /dev/null
+++ b/externals/sirit/src/instructions/memory.cpp
@@ -0,0 +1,68 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpImageTexelPointer(Id result_type, Id image, Id coordinate, Id sample) {
+ 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<spv::MemoryAccessMask> memory_access) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpLoad, result_type} << pointer << memory_access << EndOp{};
+}
+
+Id Module::OpStore(Id pointer, Id object, std::optional<spv::MemoryAccessMask> memory_access) {
+ code->Reserve(4);
+ return *code << spv::Op::OpStore << pointer << object << memory_access << EndOp{};
+}
+
+Id Module::OpAccessChain(Id result_type, Id base, std::span<const Id> indexes) {
+ 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) {
+ 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) {
+ 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<const Literal> indexes) {
+ 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<const Literal> indexes) {
+ code->Reserve(4 + indexes.size());
+ return *code << OpId{spv::Op::OpCompositeExtract, result_type} << composite << indexes
+ << EndOp{};
+}
+
+Id Module::OpCompositeConstruct(Id result_type, std::span<const Id> ids) {
+ assert(ids.size() >= 1);
+ code->Reserve(3 + ids.size());
+ return *code << OpId{spv::Op::OpCompositeConstruct, result_type} << ids << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/misc.cpp b/externals/sirit/src/instructions/misc.cpp
new file mode 100644
index 0000000000..6785346eb1
--- /dev/null
+++ b/externals/sirit/src/instructions/misc.cpp
@@ -0,0 +1,38 @@
+/* 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 "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::OpUndef(Id result_type) {
+ code->Reserve(3);
+ return *code << OpId{spv::Op::OpUndef, result_type} << EndOp{};
+}
+
+void Module::OpEmitVertex() {
+ code->Reserve(1);
+ *code << spv::Op::OpEmitVertex << EndOp{};
+}
+
+void Module::OpEndPrimitive() {
+ code->Reserve(1);
+ *code << spv::Op::OpEndPrimitive << EndOp{};
+}
+
+void Module::OpEmitStreamVertex(Id stream) {
+ code->Reserve(2);
+ *code << spv::Op::OpEmitStreamVertex << stream << EndOp{};
+}
+
+void Module::OpEndStreamPrimitive(Id stream) {
+ code->Reserve(2);
+ *code << spv::Op::OpEndStreamPrimitive << stream << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/instructions/type.cpp b/externals/sirit/src/instructions/type.cpp
new file mode 100644
index 0000000000..3509d1f472
--- /dev/null
+++ b/externals/sirit/src/instructions/type.cpp
@@ -0,0 +1,130 @@
+/* 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 <optional>
+
+#include "sirit/sirit.h"
+
+#include "stream.h"
+
+namespace Sirit {
+
+Id Module::TypeVoid() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeVoid} << EndOp{};
+}
+
+Id Module::TypeBool() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeBool} << EndOp{};
+}
+
+Id Module::TypeInt(int width, bool is_signed) {
+ declarations->Reserve(4);
+ return *declarations << OpId{spv::Op::OpTypeInt} << width << is_signed << EndOp{};
+}
+
+Id Module::TypeSInt(int width) {
+ return TypeInt(width, true);
+}
+
+Id Module::TypeUInt(int width) {
+ return TypeInt(width, false);
+}
+
+Id Module::TypeFloat(int width) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpTypeFloat} << width << EndOp{};
+}
+
+Id Module::TypeVector(Id component_type, int component_count) {
+ assert(component_count >= 2);
+ 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);
+ 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<spv::AccessQualifier> access_qualifier) {
+ declarations->Reserve(10);
+ return *declarations << OpId{spv::Op::OpTypeImage} << sampled_type << dim << depth << arrayed
+ << ms << sampled << image_format << access_qualifier << EndOp{};
+}
+
+Id Module::TypeSampler() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeSampler} << EndOp{};
+}
+
+Id Module::TypeSampledImage(Id image_type) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpTypeSampledImage} << image_type << EndOp{};
+}
+
+Id Module::TypeArray(Id element_type, Id length) {
+ declarations->Reserve(4);
+ return *declarations << OpId{spv::Op::OpTypeArray} << element_type << length << EndOp{};
+}
+
+Id Module::TypeRuntimeArray(Id element_type) {
+ declarations->Reserve(3);
+ return *declarations << OpId{spv::Op::OpTypeRuntimeArray} << element_type << EndOp{};
+}
+
+Id Module::TypeStruct(std::span<const Id> members) {
+ declarations->Reserve(2 + members.size());
+ return *declarations << OpId{spv::Op::OpTypeStruct} << members << EndOp{};
+}
+
+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) {
+ declarations->Reserve(4);
+ return *declarations << OpId{spv::Op::OpTypePointer} << storage_class << type << EndOp{};
+}
+
+Id Module::TypeFunction(Id return_type, std::span<const Id> arguments) {
+ declarations->Reserve(3 + arguments.size());
+ return *declarations << OpId{spv::Op::OpTypeFunction} << return_type << arguments << EndOp{};
+}
+
+Id Module::TypeEvent() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeEvent} << EndOp{};
+}
+
+Id Module::TypeDeviceEvent() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeDeviceEvent} << EndOp{};
+}
+
+Id Module::TypeReserveId() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeReserveId} << EndOp{};
+}
+
+Id Module::TypeQueue() {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypeQueue} << EndOp{};
+}
+
+Id Module::TypePipe(spv::AccessQualifier access_qualifier) {
+ declarations->Reserve(2);
+ return *declarations << OpId{spv::Op::OpTypePipe} << access_qualifier << EndOp{};
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/sirit.cpp b/externals/sirit/src/sirit.cpp
new file mode 100644
index 0000000000..7075f23e15
--- /dev/null
+++ b/externals/sirit/src/sirit.cpp
@@ -0,0 +1,142 @@
+/* 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 "sirit/sirit.h"
+
+#include "common_types.h"
+#include "stream.h"
+
+namespace Sirit {
+
+constexpr u32 MakeWord0(spv::Op op, size_t word_count) {
+ return static_cast<u32>(op) | static_cast<u32>(word_count) << 16;
+}
+
+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;
+
+std::vector<u32> Module::Assemble() const {
+ std::vector<u32> words = {spv::MagicNumber, version, GENERATOR_MAGIC_NUMBER, bound + 1, 0};
+ const auto insert = [&words](std::span<const u32> input) {
+ words.insert(words.end(), input.begin(), input.end());
+ };
+
+ words.reserve(words.size() + capabilities.size() * 2);
+ for (const spv::Capability capability : capabilities) {
+ insert(std::array{
+ MakeWord0(spv::Op::OpCapability, 2),
+ static_cast<u32>(capability),
+ });
+ }
+
+ for (const std::string_view extension_name : extensions) {
+ size_t string_words = WordsInString(extension_name);
+ words.push_back(MakeWord0(spv::Op::OpExtension, string_words + 1));
+ size_t insert_index = words.size();
+ words.resize(words.size() + string_words);
+ InsertStringView(words, insert_index, extension_name);
+ }
+
+ insert(ext_inst_imports->Words());
+
+ insert(std::array{
+ MakeWord0(spv::Op::OpMemoryModel, 3),
+ static_cast<u32>(addressing_model),
+ static_cast<u32>(memory_model),
+ });
+
+ 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 words;
+}
+
+void Module::PatchDeferredPhi(const std::function<Id(std::size_t index)>& func) {
+ for (const u32 phi_index : deferred_phi_nodes) {
+ const u32 first_word = code->Value(phi_index);
+ [[maybe_unused]] const spv::Op op = static_cast<spv::Op>(first_word & 0xffff);
+ assert(op == spv::Op::OpPhi);
+ const u32 num_words = first_word >> 16;
+ const u32 num_args = (num_words - 3) / 2;
+ u32 cursor = phi_index + 3;
+ for (u32 arg = 0; arg < num_args; ++arg, cursor += 2) {
+ code->SetValue(cursor, func(arg).value);
+ }
+ }
+}
+
+void Module::AddExtension(std::string extension_name) {
+ extensions.insert(std::move(extension_name));
+}
+
+void Module::AddCapability(spv::Capability capability) {
+ capabilities.insert(capability);
+}
+
+void Module::SetMemoryModel(spv::AddressingModel addressing_model_,
+ spv::MemoryModel memory_model_) {
+ addressing_model = addressing_model_;
+ memory_model = memory_model_;
+}
+
+void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point,
+ std::string_view name, std::span<const Id> 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<const Literal> literals) {
+ execution_modes->Reserve(3 + literals.size());
+ *execution_modes << spv::Op::OpExecutionMode << entry_point << mode << literals << EndOp{};
+}
+
+Id Module::AddLabel(Id label) {
+ assert(label.value != 0);
+ code->Reserve(2);
+ *code << MakeWord0(spv::Op::OpLabel, 2) << label.value;
+ return label;
+}
+
+Id Module::AddLocalVariable(Id result_type, spv::StorageClass storage_class,
+ std::optional<Id> initializer) {
+ code->Reserve(5);
+ return *code << OpId{spv::Op::OpVariable, result_type} << storage_class << initializer
+ << EndOp{};
+}
+
+Id Module::AddGlobalVariable(Id result_type, spv::StorageClass storage_class,
+ std::optional<Id> initializer) {
+ global_variables->Reserve(5);
+ return *global_variables << OpId{spv::Op::OpVariable, result_type} << storage_class
+ << initializer << EndOp{};
+}
+
+Id Module::GetGLSLstd450() {
+ if (!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;
+}
+
+} // namespace Sirit
diff --git a/externals/sirit/src/stream.cpp b/externals/sirit/src/stream.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/externals/sirit/src/stream.cpp
diff --git a/externals/sirit/src/stream.h b/externals/sirit/src/stream.h
new file mode 100644
index 0000000000..7029b6c4e7
--- /dev/null
+++ b/externals/sirit/src/stream.h
@@ -0,0 +1,266 @@
+/* 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 <bit>
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <functional>
+#include <string_view>
+#include <unordered_map>
+#include <variant>
+#include <vector>
+#include <utility>
+
+#ifndef __cpp_lib_bit_cast
+#include <cstring>
+#endif
+
+#include <spirv/unified1/spirv.hpp>
+
+#include "common_types.h"
+
+namespace Sirit {
+
+class Declarations;
+
+struct OpId {
+ OpId(spv::Op opcode_) : opcode{opcode_} {}
+ OpId(spv::Op opcode_, Id result_type_) : opcode{opcode_}, result_type{result_type_} {
+ assert(result_type.value != 0);
+ }
+
+ spv::Op opcode{};
+ Id result_type{};
+};
+
+struct EndOp {};
+
+inline size_t WordsInString(std::string_view string) {
+ return string.size() / sizeof(u32) + 1;
+}
+
+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<u32>(string[offset]) : 0u;
+ };
+
+ 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(u32* bound_) : bound{bound_} {}
+
+ void Reserve(size_t num_words) {
+ if (insert_index + num_words <= words.size()) {
+ return;
+ }
+ words.resize(insert_index + num_words);
+ }
+
+ std::span<const u32> Words() const noexcept {
+ return std::span(words.data(), insert_index);
+ }
+
+ u32 LocalAddress() const noexcept {
+ return static_cast<u32>(words.size());
+ }
+
+ u32 Value(u32 index) const noexcept {
+ return words[index];
+ }
+
+ void SetValue(u32 index, u32 value) noexcept {
+ words[index] = value;
+ }
+
+ Stream& operator<<(spv::Op op) {
+ op_index = insert_index;
+ words[insert_index++] = static_cast<u32>(op);
+ return *this;
+ }
+
+ 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;
+ }
+
+ 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) {
+#ifdef __cpp_lib_bit_cast
+ return *this << std::bit_cast<u32>(value);
+#else
+ static_assert(sizeof(float) == sizeof(u32));
+ u32 int_value;
+ std::memcpy(&int_value, &value, sizeof(int_value));
+ return *this << int_value;
+#endif
+ }
+
+ Stream& operator<<(double value) {
+#ifdef __cpp_lib_bit_cast
+ return *this << std::bit_cast<u64>(value);
+#else
+ static_assert(sizeof(double) == sizeof(u64));
+ u64 int_value;
+ std::memcpy(&int_value, &value, sizeof(int_value));
+ return *this << int_value;
+#endif
+ }
+
+ Stream& operator<<(bool value) {
+ return *this << static_cast<u32>(value ? 1 : 0);
+ }
+
+ Stream& operator<<(Id value) {
+ assert(value.value != 0);
+ 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;
+ }
+
+ Stream& operator<<(const char* string) {
+ return *this << std::string_view{string};
+ }
+
+ 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:
+ 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.data();
+ 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