diff options
Diffstat (limited to 'externals/sirit/src')
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 |